Bullet Collision Detection & Physics Library
btMultiBody.cpp
Go to the documentation of this file.
1/*
2 * PURPOSE:
3 * Class representing an articulated rigid body. Stores the body's
4 * current state, allows forces and torques to be set, handles
5 * timestepping and implements Featherstone's algorithm.
6 *
7 * COPYRIGHT:
8 * Copyright (C) Stephen Thompson, <stephen@solarflare.org.uk>, 2011-2013
9 * Portions written By Erwin Coumans: connection to LCP solver, various multibody constraints, replacing Eigen math library by Bullet LinearMath and a dedicated 6x6 matrix inverse (solveImatrix)
10 * Portions written By Jakub Stepien: support for multi-DOF constraints, introduction of spatial algebra and several other improvements
11
12 This software is provided 'as-is', without any express or implied warranty.
13 In no event will the authors be held liable for any damages arising from the use of this software.
14 Permission is granted to anyone to use this software for any purpose,
15 including commercial applications, and to alter it and redistribute it freely,
16 subject to the following restrictions:
17
18 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
19 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
20 3. This notice may not be removed or altered from any source distribution.
21
22 */
23
24#include "btMultiBody.h"
25#include "btMultiBodyLink.h"
30//#include "Bullet3Common/b3Logging.h"
31// #define INCLUDE_GYRO_TERM
32
33
34namespace
35{
36const btScalar INITIAL_SLEEP_EPSILON = btScalar(0.05); // this is a squared velocity (m^2 s^-2)
37const btScalar INITIAL_SLEEP_TIMEOUT = btScalar(2); // in seconds
38} // namespace
39
40void btMultiBody::spatialTransform(const btMatrix3x3 &rotation_matrix, // rotates vectors in 'from' frame to vectors in 'to' frame
41 const btVector3 &displacement, // vector from origin of 'from' frame to origin of 'to' frame, in 'to' coordinates
42 const btVector3 &top_in, // top part of input vector
43 const btVector3 &bottom_in, // bottom part of input vector
44 btVector3 &top_out, // top part of output vector
45 btVector3 &bottom_out) // bottom part of output vector
46{
47 top_out = rotation_matrix * top_in;
48 bottom_out = -displacement.cross(top_out) + rotation_matrix * bottom_in;
49}
50
51namespace
52{
53
54
55#if 0
56 void InverseSpatialTransform(const btMatrix3x3 &rotation_matrix,
57 const btVector3 &displacement,
58 const btVector3 &top_in,
59 const btVector3 &bottom_in,
60 btVector3 &top_out,
61 btVector3 &bottom_out)
62 {
63 top_out = rotation_matrix.transpose() * top_in;
64 bottom_out = rotation_matrix.transpose() * (bottom_in + displacement.cross(top_in));
65 }
66
67 btScalar SpatialDotProduct(const btVector3 &a_top,
68 const btVector3 &a_bottom,
69 const btVector3 &b_top,
70 const btVector3 &b_bottom)
71 {
72 return a_bottom.dot(b_top) + a_top.dot(b_bottom);
73 }
74
75 void SpatialCrossProduct(const btVector3 &a_top,
76 const btVector3 &a_bottom,
77 const btVector3 &b_top,
78 const btVector3 &b_bottom,
79 btVector3 &top_out,
80 btVector3 &bottom_out)
81 {
82 top_out = a_top.cross(b_top);
83 bottom_out = a_bottom.cross(b_top) + a_top.cross(b_bottom);
84 }
85#endif
86
87} // namespace
88
89//
90// Implementation of class btMultiBody
91//
92
94 btScalar mass,
95 const btVector3 &inertia,
96 bool fixedBase,
97 bool canSleep,
98 bool /*deprecatedUseMultiDof*/)
99 : m_baseCollider(0),
100 m_baseName(0),
101 m_basePos(0, 0, 0),
102 m_baseQuat(0, 0, 0, 1),
103 m_basePos_interpolate(0, 0, 0),
104 m_baseQuat_interpolate(0, 0, 0, 1),
105 m_baseMass(mass),
106 m_baseInertia(inertia),
107
108 m_fixedBase(fixedBase),
109 m_awake(true),
110 m_canSleep(canSleep),
111 m_canWakeup(true),
112 m_sleepTimer(0),
113 m_sleepEpsilon(INITIAL_SLEEP_EPSILON),
114 m_sleepTimeout(INITIAL_SLEEP_TIMEOUT),
115
117 m_userIndex2(-1),
118 m_userIndex(-1),
119 m_companionId(-1),
120 m_linearDamping(0.04f),
121 m_angularDamping(0.04f),
122 m_useGyroTerm(true),
123 m_maxAppliedImpulse(1000.f),
125 m_hasSelfCollision(true),
126 __posUpdated(false),
127 m_dofCount(0),
128 m_posVarCnt(0),
129 m_useRK4(false),
133{
134 m_cachedInertiaTopLeft.setValue(0, 0, 0, 0, 0, 0, 0, 0, 0);
135 m_cachedInertiaTopRight.setValue(0, 0, 0, 0, 0, 0, 0, 0, 0);
136 m_cachedInertiaLowerLeft.setValue(0, 0, 0, 0, 0, 0, 0, 0, 0);
137 m_cachedInertiaLowerRight.setValue(0, 0, 0, 0, 0, 0, 0, 0, 0);
138 m_cachedInertiaValid = false;
139
140 m_links.resize(n_links);
141 m_matrixBuf.resize(n_links + 1);
142
143 m_baseForce.setValue(0, 0, 0);
144 m_baseTorque.setValue(0, 0, 0);
145
148}
149
153
155 btScalar mass,
156 const btVector3 &inertia,
157 int parent,
158 const btQuaternion &rotParentToThis,
159 const btVector3 &parentComToThisPivotOffset,
160 const btVector3 &thisPivotToThisComOffset, bool /*deprecatedDisableParentCollision*/)
161{
162 m_links[i].m_mass = mass;
163 m_links[i].m_inertiaLocal = inertia;
164 m_links[i].m_parent = parent;
165 m_links[i].setAxisTop(0, 0., 0., 0.);
166 m_links[i].setAxisBottom(0, btVector3(0, 0, 0));
167 m_links[i].m_zeroRotParentToThis = rotParentToThis;
168 m_links[i].m_dVector = thisPivotToThisComOffset;
169 m_links[i].m_eVector = parentComToThisPivotOffset;
170
171 m_links[i].m_jointType = btMultibodyLink::eFixed;
172 m_links[i].m_dofCount = 0;
173 m_links[i].m_posVarCount = 0;
174
176
177 m_links[i].updateCacheMultiDof();
178
180}
181
183 btScalar mass,
184 const btVector3 &inertia,
185 int parent,
186 const btQuaternion &rotParentToThis,
187 const btVector3 &jointAxis,
188 const btVector3 &parentComToThisPivotOffset,
189 const btVector3 &thisPivotToThisComOffset,
190 bool disableParentCollision)
191{
192 m_dofCount += 1;
193 m_posVarCnt += 1;
194
195 m_links[i].m_mass = mass;
196 m_links[i].m_inertiaLocal = inertia;
197 m_links[i].m_parent = parent;
198 m_links[i].m_zeroRotParentToThis = rotParentToThis;
199 m_links[i].setAxisTop(0, 0., 0., 0.);
200 m_links[i].setAxisBottom(0, jointAxis);
201 m_links[i].m_eVector = parentComToThisPivotOffset;
202 m_links[i].m_dVector = thisPivotToThisComOffset;
203 m_links[i].m_cachedRotParentToThis = rotParentToThis;
204
205 m_links[i].m_jointType = btMultibodyLink::ePrismatic;
206 m_links[i].m_dofCount = 1;
207 m_links[i].m_posVarCount = 1;
208 m_links[i].m_jointPos[0] = 0.f;
209 m_links[i].m_jointTorque[0] = 0.f;
210
211 if (disableParentCollision)
213 //
214
215 m_links[i].updateCacheMultiDof();
216
218}
219
221 btScalar mass,
222 const btVector3 &inertia,
223 int parent,
224 const btQuaternion &rotParentToThis,
225 const btVector3 &jointAxis,
226 const btVector3 &parentComToThisPivotOffset,
227 const btVector3 &thisPivotToThisComOffset,
228 bool disableParentCollision)
229{
230 m_dofCount += 1;
231 m_posVarCnt += 1;
232
233 m_links[i].m_mass = mass;
234 m_links[i].m_inertiaLocal = inertia;
235 m_links[i].m_parent = parent;
236 m_links[i].m_zeroRotParentToThis = rotParentToThis;
237 m_links[i].setAxisTop(0, jointAxis);
238 m_links[i].setAxisBottom(0, jointAxis.cross(thisPivotToThisComOffset));
239 m_links[i].m_dVector = thisPivotToThisComOffset;
240 m_links[i].m_eVector = parentComToThisPivotOffset;
241
242 m_links[i].m_jointType = btMultibodyLink::eRevolute;
243 m_links[i].m_dofCount = 1;
244 m_links[i].m_posVarCount = 1;
245 m_links[i].m_jointPos[0] = 0.f;
246 m_links[i].m_jointTorque[0] = 0.f;
247
248 if (disableParentCollision)
250 //
251 m_links[i].updateCacheMultiDof();
252 //
254}
255
257 btScalar mass,
258 const btVector3 &inertia,
259 int parent,
260 const btQuaternion &rotParentToThis,
261 const btVector3 &parentComToThisPivotOffset,
262 const btVector3 &thisPivotToThisComOffset,
263 bool disableParentCollision)
264{
265 m_dofCount += 3;
266 m_posVarCnt += 4;
267
268 m_links[i].m_mass = mass;
269 m_links[i].m_inertiaLocal = inertia;
270 m_links[i].m_parent = parent;
271 m_links[i].m_zeroRotParentToThis = rotParentToThis;
272 m_links[i].m_dVector = thisPivotToThisComOffset;
273 m_links[i].m_eVector = parentComToThisPivotOffset;
274
275 m_links[i].m_jointType = btMultibodyLink::eSpherical;
276 m_links[i].m_dofCount = 3;
277 m_links[i].m_posVarCount = 4;
278 m_links[i].setAxisTop(0, 1.f, 0.f, 0.f);
279 m_links[i].setAxisTop(1, 0.f, 1.f, 0.f);
280 m_links[i].setAxisTop(2, 0.f, 0.f, 1.f);
281 m_links[i].setAxisBottom(0, m_links[i].getAxisTop(0).cross(thisPivotToThisComOffset));
282 m_links[i].setAxisBottom(1, m_links[i].getAxisTop(1).cross(thisPivotToThisComOffset));
283 m_links[i].setAxisBottom(2, m_links[i].getAxisTop(2).cross(thisPivotToThisComOffset));
284 m_links[i].m_jointPos[0] = m_links[i].m_jointPos[1] = m_links[i].m_jointPos[2] = 0.f;
285 m_links[i].m_jointPos[3] = 1.f;
286 m_links[i].m_jointTorque[0] = m_links[i].m_jointTorque[1] = m_links[i].m_jointTorque[2] = 0.f;
287
288 if (disableParentCollision)
290 //
291 m_links[i].updateCacheMultiDof();
292 //
294}
295
297 btScalar mass,
298 const btVector3 &inertia,
299 int parent,
300 const btQuaternion &rotParentToThis,
301 const btVector3 &rotationAxis,
302 const btVector3 &parentComToThisComOffset,
303 bool disableParentCollision)
304{
305 m_dofCount += 3;
306 m_posVarCnt += 3;
307
308 m_links[i].m_mass = mass;
309 m_links[i].m_inertiaLocal = inertia;
310 m_links[i].m_parent = parent;
311 m_links[i].m_zeroRotParentToThis = rotParentToThis;
312 m_links[i].m_dVector.setZero();
313 m_links[i].m_eVector = parentComToThisComOffset;
314
315 //
316 btVector3 vecNonParallelToRotAxis(1, 0, 0);
317 if (rotationAxis.normalized().dot(vecNonParallelToRotAxis) > 0.999)
318 vecNonParallelToRotAxis.setValue(0, 1, 0);
319 //
320
321 m_links[i].m_jointType = btMultibodyLink::ePlanar;
322 m_links[i].m_dofCount = 3;
323 m_links[i].m_posVarCount = 3;
324 btVector3 n = rotationAxis.normalized();
325 m_links[i].setAxisTop(0, n[0], n[1], n[2]);
326 m_links[i].setAxisTop(1, 0, 0, 0);
327 m_links[i].setAxisTop(2, 0, 0, 0);
328 m_links[i].setAxisBottom(0, 0, 0, 0);
329 btVector3 cr = m_links[i].getAxisTop(0).cross(vecNonParallelToRotAxis);
330 m_links[i].setAxisBottom(1, cr[0], cr[1], cr[2]);
331 cr = m_links[i].getAxisBottom(1).cross(m_links[i].getAxisTop(0));
332 m_links[i].setAxisBottom(2, cr[0], cr[1], cr[2]);
333 m_links[i].m_jointPos[0] = m_links[i].m_jointPos[1] = m_links[i].m_jointPos[2] = 0.f;
334 m_links[i].m_jointTorque[0] = m_links[i].m_jointTorque[1] = m_links[i].m_jointTorque[2] = 0.f;
335
336 if (disableParentCollision)
338 //
339 m_links[i].updateCacheMultiDof();
340 //
342
343 m_links[i].setAxisBottom(1, m_links[i].getAxisBottom(1).normalized());
344 m_links[i].setAxisBottom(2, m_links[i].getAxisBottom(2).normalized());
345}
346
348{
349 m_deltaV.resize(0);
350 m_deltaV.resize(6 + m_dofCount);
351 m_splitV.resize(0);
352 m_splitV.resize(6 + m_dofCount);
353 m_realBuf.resize(6 + m_dofCount + m_dofCount * m_dofCount + 6 + m_dofCount); //m_dofCount for joint-space vels + m_dofCount^2 for "D" matrices + delta-pos vector (6 base "vels" + joint "vels")
354 m_vectorBuf.resize(2 * m_dofCount); //two 3-vectors (i.e. one six-vector) for each system dof ("h" matrices)
355 m_matrixBuf.resize(m_links.size() + 1);
356 for (int i = 0; i < m_vectorBuf.size(); i++)
357 {
358 m_vectorBuf[i].setValue(0, 0, 0);
359 }
361}
362
363int btMultiBody::getParent(int link_num) const
364{
365 return m_links[link_num].m_parent;
366}
367
369{
370 return m_links[i].m_mass;
371}
372
374{
375 return m_links[i].m_inertiaLocal;
376}
377
379{
380 return m_links[i].m_jointPos[0];
381}
382
384{
385 return m_realBuf[6 + m_links[i].m_dofOffset];
386}
387
389{
390 return &m_links[i].m_jointPos[0];
391}
392
394{
395 return &m_realBuf[6 + m_links[i].m_dofOffset];
396}
397
399{
400 return &m_links[i].m_jointPos[0];
401}
402
404{
405 return &m_realBuf[6 + m_links[i].m_dofOffset];
406}
407
409{
410 m_links[i].m_jointPos[0] = q;
411 m_links[i].updateCacheMultiDof();
412}
413
414
415void btMultiBody::setJointPosMultiDof(int i, const double *q)
416{
417 for (int pos = 0; pos < m_links[i].m_posVarCount; ++pos)
418 m_links[i].m_jointPos[pos] = (btScalar)q[pos];
419
420 m_links[i].updateCacheMultiDof();
421}
422
423void btMultiBody::setJointPosMultiDof(int i, const float *q)
424{
425 for (int pos = 0; pos < m_links[i].m_posVarCount; ++pos)
426 m_links[i].m_jointPos[pos] = (btScalar)q[pos];
427
428 m_links[i].updateCacheMultiDof();
429}
430
431
432
434{
435 m_realBuf[6 + m_links[i].m_dofOffset] = qdot;
436}
437
438void btMultiBody::setJointVelMultiDof(int i, const double *qdot)
439{
440 for (int dof = 0; dof < m_links[i].m_dofCount; ++dof)
441 m_realBuf[6 + m_links[i].m_dofOffset + dof] = (btScalar)qdot[dof];
442}
443
444void btMultiBody::setJointVelMultiDof(int i, const float* qdot)
445{
446 for (int dof = 0; dof < m_links[i].m_dofCount; ++dof)
447 m_realBuf[6 + m_links[i].m_dofOffset + dof] = (btScalar)qdot[dof];
448}
449
451{
452 return m_links[i].m_cachedRVector;
453}
454
456{
457 return m_links[i].m_cachedRotParentToThis;
458}
459
461{
462 return m_links[i].m_cachedRVector_interpolate;
463}
464
466{
467 return m_links[i].m_cachedRotParentToThis_interpolate;
468}
469
471{
472 btAssert(i >= -1);
473 btAssert(i < m_links.size());
474 if ((i < -1) || (i >= m_links.size()))
475 {
477 }
478
479 btVector3 result = local_pos;
480 while (i != -1)
481 {
482 // 'result' is in frame i. transform it to frame parent(i)
483 result += getRVector(i);
484 result = quatRotate(getParentToLocalRot(i).inverse(), result);
485 i = getParent(i);
486 }
487
488 // 'result' is now in the base frame. transform it to world frame
489 result = quatRotate(getWorldToBaseRot().inverse(), result);
490 result += getBasePos();
491
492 return result;
493}
494
496{
497 btAssert(i >= -1);
498 btAssert(i < m_links.size());
499 if ((i < -1) || (i >= m_links.size()))
500 {
502 }
503
504 if (i == -1)
505 {
506 // world to base
507 return quatRotate(getWorldToBaseRot(), (world_pos - getBasePos()));
508 }
509 else
510 {
511 // find position in parent frame, then transform to current frame
512 return quatRotate(getParentToLocalRot(i), worldPosToLocal(getParent(i), world_pos)) - getRVector(i);
513 }
514}
515
517{
518 btAssert(i >= -1);
519 btAssert(i < m_links.size());
520 if ((i < -1) || (i >= m_links.size()))
521 {
523 }
524
525 btVector3 result = local_dir;
526 while (i != -1)
527 {
528 result = quatRotate(getParentToLocalRot(i).inverse(), result);
529 i = getParent(i);
530 }
531 result = quatRotate(getWorldToBaseRot().inverse(), result);
532 return result;
533}
534
536{
537 btAssert(i >= -1);
538 btAssert(i < m_links.size());
539 if ((i < -1) || (i >= m_links.size()))
540 {
542 }
543
544 if (i == -1)
545 {
546 return quatRotate(getWorldToBaseRot(), world_dir);
547 }
548 else
549 {
550 return quatRotate(getParentToLocalRot(i), worldDirToLocal(getParent(i), world_dir));
551 }
552}
553
555{
556 btMatrix3x3 result = local_frame;
557 btVector3 frameInWorld0 = localDirToWorld(i, local_frame.getColumn(0));
558 btVector3 frameInWorld1 = localDirToWorld(i, local_frame.getColumn(1));
559 btVector3 frameInWorld2 = localDirToWorld(i, local_frame.getColumn(2));
560 result.setValue(frameInWorld0[0], frameInWorld1[0], frameInWorld2[0], frameInWorld0[1], frameInWorld1[1], frameInWorld2[1], frameInWorld0[2], frameInWorld1[2], frameInWorld2[2]);
561 return result;
562}
563
565{
566 int num_links = getNumLinks();
567 // Calculates the velocities of each link (and the base) in its local frame
568 const btQuaternion& base_rot = getWorldToBaseRot();
569 omega[0] = quatRotate(base_rot, getBaseOmega());
570 vel[0] = quatRotate(base_rot, getBaseVel());
571
572 for (int i = 0; i < num_links; ++i)
573 {
574 const btMultibodyLink& link = getLink(i);
575 const int parent = link.m_parent;
576
577 // transform parent vel into this frame, store in omega[i+1], vel[i+1]
579 omega[parent + 1], vel[parent + 1],
580 omega[i + 1], vel[i + 1]);
581
582 // now add qidot * shat_i
583 const btScalar* jointVel = getJointVelMultiDof(i);
584 for (int dof = 0; dof < link.m_dofCount; ++dof)
585 {
586 omega[i + 1] += jointVel[dof] * link.getAxisTop(dof);
587 vel[i + 1] += jointVel[dof] * link.getAxisBottom(dof);
588 }
589 }
590}
591
592
594{
595 m_baseConstraintForce.setValue(0, 0, 0);
596 m_baseConstraintTorque.setValue(0, 0, 0);
597
598 for (int i = 0; i < getNumLinks(); ++i)
599 {
600 m_links[i].m_appliedConstraintForce.setValue(0, 0, 0);
601 m_links[i].m_appliedConstraintTorque.setValue(0, 0, 0);
602 }
603}
605{
606 m_baseForce.setValue(0, 0, 0);
607 m_baseTorque.setValue(0, 0, 0);
608
609 for (int i = 0; i < getNumLinks(); ++i)
610 {
611 m_links[i].m_appliedForce.setValue(0, 0, 0);
612 m_links[i].m_appliedTorque.setValue(0, 0, 0);
613 m_links[i].m_jointTorque[0] = m_links[i].m_jointTorque[1] = m_links[i].m_jointTorque[2] = m_links[i].m_jointTorque[3] = m_links[i].m_jointTorque[4] = m_links[i].m_jointTorque[5] = 0.f;
614 }
615}
616
618{
619 for (int i = 0; i < 6 + getNumDofs(); ++i)
620 {
621 m_realBuf[i] = 0.f;
622 }
623}
625{
626 m_links[i].m_appliedForce += f;
627}
628
630{
631 m_links[i].m_appliedTorque += t;
632}
633
635{
636 m_links[i].m_appliedConstraintForce += f;
637}
638
640{
641 m_links[i].m_appliedConstraintTorque += t;
642}
643
645{
646 m_links[i].m_jointTorque[0] += Q;
647}
648
650{
651 m_links[i].m_jointTorque[dof] += Q;
652}
653
655{
656 for (int dof = 0; dof < m_links[i].m_dofCount; ++dof)
657 m_links[i].m_jointTorque[dof] = Q[dof];
658}
659
661{
662 return m_links[i].m_appliedForce;
663}
664
666{
667 return m_links[i].m_appliedTorque;
668}
669
671{
672 return m_links[i].m_jointTorque[0];
673}
674
676{
677 return &m_links[i].m_jointTorque[0];
678}
679
684
689
694
696{
697 if(getBaseCollider()) {
698 int oldFlags = getBaseCollider()->getCollisionFlags();
700 getBaseCollider()->setCollisionFlags(oldFlags | dynamicType);
701 }
702}
703
704inline btMatrix3x3 outerProduct(const btVector3 &v0, const btVector3 &v1) //renamed it from vecMulVecTranspose (http://en.wikipedia.org/wiki/Outer_product); maybe it should be moved to btVector3 like dot and cross?
705{
706 btVector3 row0 = btVector3(
707 v0.x() * v1.x(),
708 v0.x() * v1.y(),
709 v0.x() * v1.z());
710 btVector3 row1 = btVector3(
711 v0.y() * v1.x(),
712 v0.y() * v1.y(),
713 v0.y() * v1.z());
714 btVector3 row2 = btVector3(
715 v0.z() * v1.x(),
716 v0.z() * v1.y(),
717 v0.z() * v1.z());
718
719 btMatrix3x3 m(row0[0], row0[1], row0[2],
720 row1[0], row1[1], row1[2],
721 row2[0], row2[1], row2[2]);
722 return m;
723}
724
725#define vecMulVecTranspose(v0, v1Transposed) outerProduct(v0, v1Transposed)
726//
727
732 bool isConstraintPass,
733 bool jointFeedbackInWorldSpace,
734 bool jointFeedbackInJointFrame)
735{
736 // Implement Featherstone's algorithm to calculate joint accelerations (q_double_dot)
737 // and the base linear & angular accelerations.
738
739 // We apply damping forces in this routine as well as any external forces specified by the
740 // caller (via addBaseForce etc).
741
742 // output should point to an array of 6 + num_links reals.
743 // Format is: 3 angular accelerations (in world frame), 3 linear accelerations (in world frame),
744 // num_links joint acceleration values.
745
746 // We added support for multi degree of freedom (multi dof) joints.
747 // In addition we also can compute the joint reaction forces. This is performed in a second pass,
748 // so that we can include the effect of the constraint solver forces (computed in the PGS LCP solver)
749
751
752 int num_links = getNumLinks();
753
754 const btScalar DAMPING_K1_LINEAR = m_linearDamping;
755 const btScalar DAMPING_K2_LINEAR = m_linearDamping;
756
757 const btScalar DAMPING_K1_ANGULAR = m_angularDamping;
758 const btScalar DAMPING_K2_ANGULAR = m_angularDamping;
759
760 const btVector3 base_vel = getBaseVel();
761 const btVector3 base_omega = getBaseOmega();
762
763 // Temporary matrices/vectors -- use scratch space from caller
764 // so that we don't have to keep reallocating every frame
765
766 scratch_r.resize(2 * m_dofCount + 7); //multidof? ("Y"s use it and it is used to store qdd) => 2 x m_dofCount
767 scratch_v.resize(8 * num_links + 6);
768 scratch_m.resize(4 * num_links + 4);
769
770 //btScalar * r_ptr = &scratch_r[0];
771 btScalar *output = &scratch_r[m_dofCount]; // "output" holds the q_double_dot results
772 btVector3 *v_ptr = &scratch_v[0];
773
774 // vhat_i (top = angular, bottom = linear part)
776 v_ptr += num_links * 2 + 2;
777 //
778 // zhat_i^A
779 btSpatialForceVector *zeroAccSpatFrc = (btSpatialForceVector *)v_ptr;
780 v_ptr += num_links * 2 + 2;
781 //
782 // chat_i (note NOT defined for the base)
783 btSpatialMotionVector *spatCoriolisAcc = (btSpatialMotionVector *)v_ptr;
784 v_ptr += num_links * 2;
785 //
786 // Ihat_i^A.
787 btSymmetricSpatialDyad *spatInertia = (btSymmetricSpatialDyad *)&scratch_m[num_links + 1];
788
789 // Cached 3x3 rotation matrices from parent frame to this frame.
790 btMatrix3x3 *rot_from_parent = &m_matrixBuf[0];
791 btMatrix3x3 *rot_from_world = &scratch_m[0];
792
793 // hhat_i, ahat_i
794 // hhat is NOT stored for the base (but ahat is)
797 v_ptr += num_links * 2 + 2;
798 //
799 // Y_i, invD_i
800 btScalar *invD = m_dofCount > 0 ? &m_realBuf[6 + m_dofCount] : 0;
801 btScalar *Y = &scratch_r[0];
802 //
803 //aux variables
804 btSpatialMotionVector spatJointVel; //spatial velocity due to the joint motion (i.e. without predecessors' influence)
805 btScalar D[36]; //"D" matrix; it's dofxdof for each body so asingle 6x6 D matrix will do
806 btScalar invD_times_Y[6]; //D^{-1} * Y [dofxdof x dofx1 = dofx1] <=> D^{-1} * u; better moved to buffers since it is recalced in calcAccelerationDeltasMultiDof; num_dof of btScalar would cover all bodies
807 btSpatialMotionVector result; //holds results of the SolveImatrix op; it is a spatial motion vector (accel)
808 btScalar Y_minus_hT_a[6]; //Y - h^{T} * a; it's dofx1 for each body so a single 6x1 temp is enough
809 btSpatialForceVector spatForceVecTemps[6]; //6 temporary spatial force vectors
810 btSpatialTransformationMatrix fromParent; //spatial transform from parent to child
811 btSymmetricSpatialDyad dyadTemp; //inertia matrix temp
813 fromWorld.m_trnVec.setZero();
815
816 // ptr to the joint accel part of the output
817 btScalar *joint_accel = output + 6;
818
819 // Start of the algorithm proper.
820
821 // First 'upward' loop.
822 // Combines CompTreeLinkVelocities and InitTreeLinks from Mirtich.
823
824 rot_from_parent[0] = btMatrix3x3(m_baseQuat); //m_baseQuat assumed to be alias!?
825
826 //create the vector of spatial velocity of the base by transforming global-coor linear and angular velocities into base-local coordinates
827 spatVel[0].setVector(rot_from_parent[0] * base_omega, rot_from_parent[0] * base_vel);
828
830 {
831 zeroAccSpatFrc[0].setZero();
832 }
833 else
834 {
835 const btVector3 &baseForce = isConstraintPass ? m_baseConstraintForce : m_baseForce;
836 const btVector3 &baseTorque = isConstraintPass ? m_baseConstraintTorque : m_baseTorque;
837 //external forces
838 zeroAccSpatFrc[0].setVector(-(rot_from_parent[0] * baseTorque), -(rot_from_parent[0] * baseForce));
839
840 //adding damping terms (only)
841 const btScalar linDampMult = 1., angDampMult = 1.;
842 zeroAccSpatFrc[0].addVector(angDampMult * m_baseInertia * spatVel[0].getAngular() * (DAMPING_K1_ANGULAR + DAMPING_K2_ANGULAR * spatVel[0].getAngular().safeNorm()),
843 linDampMult * m_baseMass * spatVel[0].getLinear() * (DAMPING_K1_LINEAR + DAMPING_K2_LINEAR * spatVel[0].getLinear().safeNorm()));
844
845 //
846 //p += vhat x Ihat vhat - done in a simpler way
847 if (m_useGyroTerm)
848 zeroAccSpatFrc[0].addAngular(spatVel[0].getAngular().cross(m_baseInertia * spatVel[0].getAngular()));
849 //
850 zeroAccSpatFrc[0].addLinear(m_baseMass * spatVel[0].getAngular().cross(spatVel[0].getLinear()));
851 }
852
853 //init the spatial AB inertia (it has the simple form thanks to choosing local body frames origins at their COMs)
854 spatInertia[0].setMatrix(btMatrix3x3(0, 0, 0, 0, 0, 0, 0, 0, 0),
855 //
857 0, m_baseMass, 0,
858 0, 0, m_baseMass),
859 //
860 btMatrix3x3(m_baseInertia[0], 0, 0,
861 0, m_baseInertia[1], 0,
862 0, 0, m_baseInertia[2]));
863
864 rot_from_world[0] = rot_from_parent[0];
865
866 //
867 for (int i = 0; i < num_links; ++i)
868 {
869 const int parent = m_links[i].m_parent;
870 rot_from_parent[i + 1] = btMatrix3x3(m_links[i].m_cachedRotParentToThis);
871 rot_from_world[i + 1] = rot_from_parent[i + 1] * rot_from_world[parent + 1];
872
873 fromParent.m_rotMat = rot_from_parent[i + 1];
874 fromParent.m_trnVec = m_links[i].m_cachedRVector;
875 fromWorld.m_rotMat = rot_from_world[i + 1];
876 fromParent.transform(spatVel[parent + 1], spatVel[i + 1]);
877
878 // now set vhat_i to its true value by doing
879 // vhat_i += qidot * shat_i
881 {
882 spatJointVel.setZero();
883
884 for (int dof = 0; dof < m_links[i].m_dofCount; ++dof)
885 spatJointVel += m_links[i].m_axes[dof] * getJointVelMultiDof(i)[dof];
886
887 // remember vhat_i is really vhat_p(i) (but in current frame) at this point => we need to add velocity across the inboard joint
888 spatVel[i + 1] += spatJointVel;
889
890 //
891 // vhat_i is vhat_p(i) transformed to local coors + the velocity across the i-th inboard joint
892 //spatVel[i+1] = fromParent * spatVel[parent+1] + spatJointVel;
893 }
894 else
895 {
896 fromWorld.transformRotationOnly(m_links[i].m_absFrameTotVelocity, spatVel[i + 1]);
897 fromWorld.transformRotationOnly(m_links[i].m_absFrameLocVelocity, spatJointVel);
898 }
899
900 // we can now calculate chat_i
901 spatVel[i + 1].cross(spatJointVel, spatCoriolisAcc[i]);
902
903 // calculate zhat_i^A
904 //
906 {
907 zeroAccSpatFrc[i].setZero();
908 }
909 else{
910 //external forces
911 btVector3 linkAppliedForce = isConstraintPass ? m_links[i].m_appliedConstraintForce : m_links[i].m_appliedForce;
912 btVector3 linkAppliedTorque = isConstraintPass ? m_links[i].m_appliedConstraintTorque : m_links[i].m_appliedTorque;
913
914 zeroAccSpatFrc[i + 1].setVector(-(rot_from_world[i + 1] * linkAppliedTorque), -(rot_from_world[i + 1] * linkAppliedForce));
915
916#if 0
917 {
918
919 b3Printf("stepVelocitiesMultiDof zeroAccSpatFrc[%d] linear:%f,%f,%f, angular:%f,%f,%f",
920 i+1,
921 zeroAccSpatFrc[i+1].m_topVec[0],
922 zeroAccSpatFrc[i+1].m_topVec[1],
923 zeroAccSpatFrc[i+1].m_topVec[2],
924
925 zeroAccSpatFrc[i+1].m_bottomVec[0],
926 zeroAccSpatFrc[i+1].m_bottomVec[1],
927 zeroAccSpatFrc[i+1].m_bottomVec[2]);
928 }
929#endif
930 //
931 //adding damping terms (only)
932 btScalar linDampMult = 1., angDampMult = 1.;
933 zeroAccSpatFrc[i + 1].addVector(angDampMult * m_links[i].m_inertiaLocal * spatVel[i + 1].getAngular() * (DAMPING_K1_ANGULAR + DAMPING_K2_ANGULAR * spatVel[i + 1].getAngular().safeNorm()),
934 linDampMult * m_links[i].m_mass * spatVel[i + 1].getLinear() * (DAMPING_K1_LINEAR + DAMPING_K2_LINEAR * spatVel[i + 1].getLinear().safeNorm()));
935 //p += vhat x Ihat vhat - done in a simpler way
936 if (m_useGyroTerm)
937 zeroAccSpatFrc[i + 1].addAngular(spatVel[i + 1].getAngular().cross(m_links[i].m_inertiaLocal * spatVel[i + 1].getAngular()));
938 //
939 if (!isConstraintPass)
940 zeroAccSpatFrc[i + 1].addLinear(m_links[i].m_mass * spatVel[i + 1].getAngular().cross(spatVel[i + 1].getLinear()));
941 //
942 //btVector3 temp = m_links[i].m_mass * spatVel[i+1].getAngular().cross(spatVel[i+1].getLinear());
944 //btScalar parOmegaMod = temp.length();
945 //btScalar parOmegaModMax = 1000;
946 //if(parOmegaMod > parOmegaModMax)
947 // temp *= parOmegaModMax / parOmegaMod;
948 //zeroAccSpatFrc[i+1].addLinear(temp);
949 //printf("|zeroAccSpatFrc[%d]| = %.4f\n", i+1, temp.length());
950 //temp = spatCoriolisAcc[i].getLinear();
951 //printf("|spatCoriolisAcc[%d]| = %.4f\n", i+1, temp.length());
952 }
953
954 // calculate Ihat_i^A
955 //init the spatial AB inertia (it has the simple form thanks to choosing local body frames origins at their COMs)
956 spatInertia[i + 1].setMatrix(btMatrix3x3(0, 0, 0, 0, 0, 0, 0, 0, 0),
957 //
958 btMatrix3x3(m_links[i].m_mass, 0, 0,
959 0, m_links[i].m_mass, 0,
960 0, 0, m_links[i].m_mass),
961 //
962 btMatrix3x3(m_links[i].m_inertiaLocal[0], 0, 0,
963 0, m_links[i].m_inertiaLocal[1], 0,
964 0, 0, m_links[i].m_inertiaLocal[2]));
965
966 //printf("w[%d] = [%.4f %.4f %.4f]\n", i, vel_top_angular[i+1].x(), vel_top_angular[i+1].y(), vel_top_angular[i+1].z());
967 //printf("v[%d] = [%.4f %.4f %.4f]\n", i, vel_bottom_linear[i+1].x(), vel_bottom_linear[i+1].y(), vel_bottom_linear[i+1].z());
968 //printf("c[%d] = [%.4f %.4f %.4f]\n", i, coriolis_bottom_linear[i].x(), coriolis_bottom_linear[i].y(), coriolis_bottom_linear[i].z());
969 }
970
971 // 'Downward' loop.
972 // (part of TreeForwardDynamics in Mirtich.)
973 for (int i = num_links - 1; i >= 0; --i)
974 {
976 continue;
977 const int parent = m_links[i].m_parent;
978 fromParent.m_rotMat = rot_from_parent[i + 1];
979 fromParent.m_trnVec = m_links[i].m_cachedRVector;
980
981 for (int dof = 0; dof < m_links[i].m_dofCount; ++dof)
982 {
983 btSpatialForceVector &hDof = h[m_links[i].m_dofOffset + dof];
984 //
985 hDof = spatInertia[i + 1] * m_links[i].m_axes[dof];
986 //
987 btScalar jointTorque = 0;
988 if (isConstraintPass) jointTorque = 0;
989 else jointTorque = m_links[i].m_jointTorque[dof];
990 Y[m_links[i].m_dofOffset + dof] = jointTorque - m_links[i].m_axes[dof].dot(zeroAccSpatFrc[i + 1]) - spatCoriolisAcc[i].dot(hDof);
991
992 }
993 for (int dof = 0; dof < m_links[i].m_dofCount; ++dof)
994 {
995 btScalar *D_row = &D[dof * m_links[i].m_dofCount];
996 for (int dof2 = 0; dof2 < m_links[i].m_dofCount; ++dof2)
997 {
998 const btSpatialForceVector &hDof2 = h[m_links[i].m_dofOffset + dof2];
999 D_row[dof2] = m_links[i].m_axes[dof].dot(hDof2);
1000 }
1001 }
1002
1003 btScalar *invDi = &invD[m_links[i].m_dofOffset * m_links[i].m_dofOffset];
1004 switch (m_links[i].m_jointType)
1005 {
1008 {
1009 if (D[0] >= SIMD_EPSILON)
1010 {
1011 invDi[0] = 1.0f / D[0];
1012 }
1013 else
1014 {
1015 invDi[0] = 0;
1016 }
1017 break;
1018 }
1021 {
1022 const btMatrix3x3 D3x3(D[0], D[1], D[2], D[3], D[4], D[5], D[6], D[7], D[8]);
1023 const btMatrix3x3 invD3x3(D3x3.inverse());
1024
1025 //unroll the loop?
1026 for (int row = 0; row < 3; ++row)
1027 {
1028 for (int col = 0; col < 3; ++col)
1029 {
1030 invDi[row * 3 + col] = invD3x3[row][col];
1031 }
1032 }
1033
1034 break;
1035 }
1036 default:
1037 {
1038 }
1039 }
1040
1041 //determine h*D^{-1}
1042 for (int dof = 0; dof < m_links[i].m_dofCount; ++dof)
1043 {
1044 spatForceVecTemps[dof].setZero();
1045
1046 for (int dof2 = 0; dof2 < m_links[i].m_dofCount; ++dof2)
1047 {
1048 const btSpatialForceVector &hDof2 = h[m_links[i].m_dofOffset + dof2];
1049 //
1050 spatForceVecTemps[dof] += hDof2 * invDi[dof2 * m_links[i].m_dofCount + dof];
1051 }
1052 }
1053
1054 dyadTemp = spatInertia[i + 1];
1055
1056 //determine (h*D^{-1}) * h^{T}
1057 for (int dof = 0; dof < m_links[i].m_dofCount; ++dof)
1058 {
1059 const btSpatialForceVector &hDof = h[m_links[i].m_dofOffset + dof];
1060 //
1061 dyadTemp -= symmetricSpatialOuterProduct(hDof, spatForceVecTemps[dof]);
1062 }
1063
1064 fromParent.transformInverse(dyadTemp, spatInertia[parent + 1], btSpatialTransformationMatrix::Add);
1065
1066 for (int dof = 0; dof < m_links[i].m_dofCount; ++dof)
1067 {
1068 invD_times_Y[dof] = 0.f;
1069
1070 for (int dof2 = 0; dof2 < m_links[i].m_dofCount; ++dof2)
1071 {
1072 invD_times_Y[dof] += invDi[dof * m_links[i].m_dofCount + dof2] * Y[m_links[i].m_dofOffset + dof2];
1073 }
1074 }
1075
1076 spatForceVecTemps[0] = zeroAccSpatFrc[i + 1] + spatInertia[i + 1] * spatCoriolisAcc[i];
1077
1078 for (int dof = 0; dof < m_links[i].m_dofCount; ++dof)
1079 {
1080 const btSpatialForceVector &hDof = h[m_links[i].m_dofOffset + dof];
1081 //
1082 spatForceVecTemps[0] += hDof * invD_times_Y[dof];
1083 }
1084
1085 fromParent.transformInverse(spatForceVecTemps[0], spatForceVecTemps[1]);
1086
1087 zeroAccSpatFrc[parent + 1] += spatForceVecTemps[1];
1088 }
1089
1090 // Second 'upward' loop
1091 // (part of TreeForwardDynamics in Mirtich)
1092
1094 {
1095 spatAcc[0].setZero();
1096 }
1097 else
1098 {
1099 if (num_links > 0)
1100 {
1101 m_cachedInertiaValid = true;
1102 m_cachedInertiaTopLeft = spatInertia[0].m_topLeftMat;
1103 m_cachedInertiaTopRight = spatInertia[0].m_topRightMat;
1106 }
1107
1108 solveImatrix(zeroAccSpatFrc[0], result);
1109 spatAcc[0] = -result;
1110 }
1111
1112 // now do the loop over the m_links
1113 for (int i = 0; i < num_links; ++i)
1114 {
1115 // qdd = D^{-1} * (Y - h^{T}*apar) = (S^{T}*I*S)^{-1} * (tau - S^{T}*I*cor - S^{T}*zeroAccFrc - S^{T}*I*apar)
1116 // a = apar + cor + Sqdd
1117 //or
1118 // qdd = D^{-1} * (Y - h^{T}*(apar+cor))
1119 // a = apar + Sqdd
1120
1121 const int parent = m_links[i].m_parent;
1122 fromParent.m_rotMat = rot_from_parent[i + 1];
1123 fromParent.m_trnVec = m_links[i].m_cachedRVector;
1124
1125 fromParent.transform(spatAcc[parent + 1], spatAcc[i + 1]);
1126
1128 {
1129 for (int dof = 0; dof < m_links[i].m_dofCount; ++dof)
1130 {
1131 const btSpatialForceVector &hDof = h[m_links[i].m_dofOffset + dof];
1132 //
1133 Y_minus_hT_a[dof] = Y[m_links[i].m_dofOffset + dof] - spatAcc[i + 1].dot(hDof);
1134 }
1135 btScalar *invDi = &invD[m_links[i].m_dofOffset * m_links[i].m_dofOffset];
1136 //D^{-1} * (Y - h^{T}*apar)
1137 mulMatrix(invDi, Y_minus_hT_a, m_links[i].m_dofCount, m_links[i].m_dofCount, m_links[i].m_dofCount, 1, &joint_accel[m_links[i].m_dofOffset]);
1138
1139 spatAcc[i + 1] += spatCoriolisAcc[i];
1140
1141 for (int dof = 0; dof < m_links[i].m_dofCount; ++dof)
1142 spatAcc[i + 1] += m_links[i].m_axes[dof] * joint_accel[m_links[i].m_dofOffset + dof];
1143 }
1144
1145 if (m_links[i].m_jointFeedback)
1146 {
1148
1149 btVector3 angularBotVec = (spatInertia[i + 1] * spatAcc[i + 1] + zeroAccSpatFrc[i + 1]).m_bottomVec;
1150 btVector3 linearTopVec = (spatInertia[i + 1] * spatAcc[i + 1] + zeroAccSpatFrc[i + 1]).m_topVec;
1151
1152 if (jointFeedbackInJointFrame)
1153 {
1154 //shift the reaction forces to the joint frame
1155 //linear (force) component is the same
1156 //shift the angular (torque, moment) component using the relative position, m_links[i].m_dVector
1157 angularBotVec = angularBotVec - linearTopVec.cross(m_links[i].m_dVector);
1158 }
1159
1160 if (jointFeedbackInWorldSpace)
1161 {
1162 if (isConstraintPass)
1163 {
1164 m_links[i].m_jointFeedback->m_reactionForces.m_bottomVec += m_links[i].m_cachedWorldTransform.getBasis() * angularBotVec;
1165 m_links[i].m_jointFeedback->m_reactionForces.m_topVec += m_links[i].m_cachedWorldTransform.getBasis() * linearTopVec;
1166 }
1167 else
1168 {
1169 m_links[i].m_jointFeedback->m_reactionForces.m_bottomVec = m_links[i].m_cachedWorldTransform.getBasis() * angularBotVec;
1170 m_links[i].m_jointFeedback->m_reactionForces.m_topVec = m_links[i].m_cachedWorldTransform.getBasis() * linearTopVec;
1171 }
1172 }
1173 else
1174 {
1175 if (isConstraintPass)
1176 {
1177 m_links[i].m_jointFeedback->m_reactionForces.m_bottomVec += angularBotVec;
1178 m_links[i].m_jointFeedback->m_reactionForces.m_topVec += linearTopVec;
1179 }
1180 else
1181 {
1182 m_links[i].m_jointFeedback->m_reactionForces.m_bottomVec = angularBotVec;
1183 m_links[i].m_jointFeedback->m_reactionForces.m_topVec = linearTopVec;
1184 }
1185 }
1186 }
1187 }
1188
1189 // transform base accelerations back to the world frame.
1190 const btVector3 omegadot_out = rot_from_parent[0].transpose() * spatAcc[0].getAngular();
1191 output[0] = omegadot_out[0];
1192 output[1] = omegadot_out[1];
1193 output[2] = omegadot_out[2];
1194
1195 const btVector3 vdot_out = rot_from_parent[0].transpose() * (spatAcc[0].getLinear() + spatVel[0].getAngular().cross(spatVel[0].getLinear()));
1196 output[3] = vdot_out[0];
1197 output[4] = vdot_out[1];
1198 output[5] = vdot_out[2];
1199
1201 //printf("q = [");
1202 //printf("%.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f ", m_baseQuat.x(), m_baseQuat.y(), m_baseQuat.z(), m_baseQuat.w(), m_basePos.x(), m_basePos.y(), m_basePos.z());
1203 //for(int link = 0; link < getNumLinks(); ++link)
1204 // for(int dof = 0; dof < m_links[link].m_dofCount; ++dof)
1205 // printf("%.6f ", m_links[link].m_jointPos[dof]);
1206 //printf("]\n");
1208 //printf("qd = [");
1209 //for(int dof = 0; dof < getNumDofs() + 6; ++dof)
1210 // printf("%.6f ", m_realBuf[dof]);
1211 //printf("]\n");
1212 //printf("qdd = [");
1213 //for(int dof = 0; dof < getNumDofs() + 6; ++dof)
1214 // printf("%.6f ", output[dof]);
1215 //printf("]\n");
1217
1218 // Final step: add the accelerations (times dt) to the velocities.
1219
1220 if (!isConstraintPass)
1221 {
1222 if (dt > 0.)
1224 }
1226 //btScalar angularThres = 1;
1227 //btScalar maxAngVel = 0.;
1228 //bool scaleDown = 1.;
1229 //for(int link = 0; link < m_links.size(); ++link)
1230 //{
1231 // if(spatVel[link+1].getAngular().length() > maxAngVel)
1232 // {
1233 // maxAngVel = spatVel[link+1].getAngular().length();
1234 // scaleDown = angularThres / spatVel[link+1].getAngular().length();
1235 // break;
1236 // }
1237 //}
1238
1239 //if(scaleDown != 1.)
1240 //{
1241 // for(int link = 0; link < m_links.size(); ++link)
1242 // {
1243 // if(m_links[link].m_jointType == btMultibodyLink::eRevolute || m_links[link].m_jointType == btMultibodyLink::eSpherical)
1244 // {
1245 // for(int dof = 0; dof < m_links[link].m_dofCount; ++dof)
1246 // getJointVelMultiDof(link)[dof] *= scaleDown;
1247 // }
1248 // }
1249 //}
1251
1254 {
1255 for (int i = 0; i < num_links; ++i)
1256 {
1257 const int parent = m_links[i].m_parent;
1258 //rot_from_parent[i+1] = btMatrix3x3(m_links[i].m_cachedRotParentToThis); /// <- done
1259 //rot_from_world[i+1] = rot_from_parent[i+1] * rot_from_world[parent+1]; /// <- done
1260
1261 fromParent.m_rotMat = rot_from_parent[i + 1];
1262 fromParent.m_trnVec = m_links[i].m_cachedRVector;
1263 fromWorld.m_rotMat = rot_from_world[i + 1];
1264
1265 // vhat_i = i_xhat_p(i) * vhat_p(i)
1266 fromParent.transform(spatVel[parent + 1], spatVel[i + 1]);
1267 //nice alternative below (using operator *) but it generates temps
1269
1270 // now set vhat_i to its true value by doing
1271 // vhat_i += qidot * shat_i
1272 spatJointVel.setZero();
1273
1274 for (int dof = 0; dof < m_links[i].m_dofCount; ++dof)
1275 spatJointVel += m_links[i].m_axes[dof] * getJointVelMultiDof(i)[dof];
1276
1277 // remember vhat_i is really vhat_p(i) (but in current frame) at this point => we need to add velocity across the inboard joint
1278 spatVel[i + 1] += spatJointVel;
1279
1280 fromWorld.transformInverseRotationOnly(spatVel[i + 1], m_links[i].m_absFrameTotVelocity);
1281 fromWorld.transformInverseRotationOnly(spatJointVel, m_links[i].m_absFrameLocVelocity);
1282 }
1283 }
1284}
1285
1286void btMultiBody::solveImatrix(const btVector3 &rhs_top, const btVector3 &rhs_bot, btScalar result[6]) const
1287{
1288 int num_links = getNumLinks();
1290 if (num_links == 0)
1291 {
1292 // in the case of 0 m_links (i.e. a plain rigid body, not a multibody) rhs * invI is easier
1293
1295 {
1296 result[0] = rhs_bot[0] / m_baseInertia[0];
1297 result[1] = rhs_bot[1] / m_baseInertia[1];
1298 result[2] = rhs_bot[2] / m_baseInertia[2];
1299 }
1300 else
1301 {
1302 result[0] = 0;
1303 result[1] = 0;
1304 result[2] = 0;
1305 }
1306 if (m_baseMass >= SIMD_EPSILON)
1307 {
1308 result[3] = rhs_top[0] / m_baseMass;
1309 result[4] = rhs_top[1] / m_baseMass;
1310 result[5] = rhs_top[2] / m_baseMass;
1311 }
1312 else
1313 {
1314 result[3] = 0;
1315 result[4] = 0;
1316 result[5] = 0;
1317 }
1318 }
1319 else
1320 {
1322 {
1323 for (int i = 0; i < 6; i++)
1324 {
1325 result[i] = 0.f;
1326 }
1327 return;
1328 }
1331 btMatrix3x3 Binv = m_cachedInertiaTopRight.inverse() * -1.f;
1334 tmp = invIupper_right * m_cachedInertiaLowerRight;
1335 btMatrix3x3 invI_upper_left = (tmp * Binv);
1336 btMatrix3x3 invI_lower_right = (invI_upper_left).transpose();
1337 tmp = m_cachedInertiaTopLeft * invI_upper_left;
1338 tmp[0][0] -= 1.0;
1339 tmp[1][1] -= 1.0;
1340 tmp[2][2] -= 1.0;
1341 btMatrix3x3 invI_lower_left = (Binv * tmp);
1342
1343 //multiply result = invI * rhs
1344 {
1345 btVector3 vtop = invI_upper_left * rhs_top;
1346 btVector3 tmp;
1347 tmp = invIupper_right * rhs_bot;
1348 vtop += tmp;
1349 btVector3 vbot = invI_lower_left * rhs_top;
1350 tmp = invI_lower_right * rhs_bot;
1351 vbot += tmp;
1352 result[0] = vtop[0];
1353 result[1] = vtop[1];
1354 result[2] = vtop[2];
1355 result[3] = vbot[0];
1356 result[4] = vbot[1];
1357 result[5] = vbot[2];
1358 }
1359 }
1360}
1362{
1363 int num_links = getNumLinks();
1365 if (num_links == 0)
1366 {
1367 // in the case of 0 m_links (i.e. a plain rigid body, not a multibody) rhs * invI is easier
1369 {
1370 result.setAngular(rhs.getAngular() / m_baseInertia);
1371 }
1372 else
1373 {
1374 result.setAngular(btVector3(0, 0, 0));
1375 }
1376 if (m_baseMass >= SIMD_EPSILON)
1377 {
1378 result.setLinear(rhs.getLinear() / m_baseMass);
1379 }
1380 else
1381 {
1382 result.setLinear(btVector3(0, 0, 0));
1383 }
1384 }
1385 else
1386 {
1390 {
1391 result.setLinear(btVector3(0, 0, 0));
1392 result.setAngular(btVector3(0, 0, 0));
1393 result.setVector(btVector3(0, 0, 0), btVector3(0, 0, 0));
1394 return;
1395 }
1396 btMatrix3x3 Binv = m_cachedInertiaTopRight.inverse() * -1.f;
1399 tmp = invIupper_right * m_cachedInertiaLowerRight;
1400 btMatrix3x3 invI_upper_left = (tmp * Binv);
1401 btMatrix3x3 invI_lower_right = (invI_upper_left).transpose();
1402 tmp = m_cachedInertiaTopLeft * invI_upper_left;
1403 tmp[0][0] -= 1.0;
1404 tmp[1][1] -= 1.0;
1405 tmp[2][2] -= 1.0;
1406 btMatrix3x3 invI_lower_left = (Binv * tmp);
1407
1408 //multiply result = invI * rhs
1409 {
1410 btVector3 vtop = invI_upper_left * rhs.getLinear();
1411 btVector3 tmp;
1412 tmp = invIupper_right * rhs.getAngular();
1413 vtop += tmp;
1414 btVector3 vbot = invI_lower_left * rhs.getLinear();
1415 tmp = invI_lower_right * rhs.getAngular();
1416 vbot += tmp;
1417 result.setVector(vtop, vbot);
1418 }
1419 }
1420}
1421
1422void btMultiBody::mulMatrix(const btScalar *pA, const btScalar *pB, int rowsA, int colsA, int rowsB, int colsB, btScalar *pC) const
1423{
1424 for (int row = 0; row < rowsA; row++)
1425 {
1426 for (int col = 0; col < colsB; col++)
1427 {
1428 pC[row * colsB + col] = 0.f;
1429 for (int inner = 0; inner < rowsB; inner++)
1430 {
1431 pC[row * colsB + col] += pA[row * colsA + inner] * pB[col + inner * colsB];
1432 }
1433 }
1434 }
1435}
1436
1439{
1440 // Temporary matrices/vectors -- use scratch space from caller
1441 // so that we don't have to keep reallocating every frame
1442
1443 int num_links = getNumLinks();
1444 scratch_r.resize(m_dofCount);
1445 scratch_v.resize(4 * num_links + 4);
1446
1447 btScalar *r_ptr = m_dofCount ? &scratch_r[0] : 0;
1448 btVector3 *v_ptr = &scratch_v[0];
1449
1450 // zhat_i^A (scratch space)
1451 btSpatialForceVector *zeroAccSpatFrc = (btSpatialForceVector *)v_ptr;
1452 v_ptr += num_links * 2 + 2;
1453
1454 // rot_from_parent (cached from calcAccelerations)
1455 const btMatrix3x3 *rot_from_parent = &m_matrixBuf[0];
1456
1457 // hhat (cached), accel (scratch)
1458 // hhat is NOT stored for the base (but ahat is)
1460 btSpatialMotionVector *spatAcc = (btSpatialMotionVector *)v_ptr;
1461 v_ptr += num_links * 2 + 2;
1462
1463 // Y_i (scratch), invD_i (cached)
1464 const btScalar *invD = m_dofCount > 0 ? &m_realBuf[6 + m_dofCount] : 0;
1465 btScalar *Y = r_ptr;
1467 //aux variables
1468 btScalar invD_times_Y[6]; //D^{-1} * Y [dofxdof x dofx1 = dofx1] <=> D^{-1} * u; better moved to buffers since it is recalced in calcAccelerationDeltasMultiDof; num_dof of btScalar would cover all bodies
1469 btSpatialMotionVector result; //holds results of the SolveImatrix op; it is a spatial motion vector (accel)
1470 btScalar Y_minus_hT_a[6]; //Y - h^{T} * a; it's dofx1 for each body so a single 6x1 temp is enough
1471 btSpatialForceVector spatForceVecTemps[6]; //6 temporary spatial force vectors
1474
1475 // First 'upward' loop.
1476 // Combines CompTreeLinkVelocities and InitTreeLinks from Mirtich.
1477
1478 // Fill in zero_acc
1479 // -- set to force/torque on the base, zero otherwise
1481 {
1482 zeroAccSpatFrc[0].setZero();
1483 }
1484 else
1485 {
1486 //test forces
1487 fromParent.m_rotMat = rot_from_parent[0];
1488 fromParent.transformRotationOnly(btSpatialForceVector(-force[0], -force[1], -force[2], -force[3], -force[4], -force[5]), zeroAccSpatFrc[0]);
1489 }
1490 for (int i = 0; i < num_links; ++i)
1491 {
1492 zeroAccSpatFrc[i + 1].setZero();
1493 }
1494
1495 // 'Downward' loop.
1496 // (part of TreeForwardDynamics in Mirtich.)
1497 for (int i = num_links - 1; i >= 0; --i)
1498 {
1500 continue;
1501 const int parent = m_links[i].m_parent;
1502 fromParent.m_rotMat = rot_from_parent[i + 1];
1503 fromParent.m_trnVec = m_links[i].m_cachedRVector;
1504
1505 for (int dof = 0; dof < m_links[i].m_dofCount; ++dof)
1506 {
1507 Y[m_links[i].m_dofOffset + dof] = force[6 + m_links[i].m_dofOffset + dof] - m_links[i].m_axes[dof].dot(zeroAccSpatFrc[i + 1]);
1508 }
1509
1510 btVector3 in_top, in_bottom, out_top, out_bottom;
1511 const btScalar *invDi = &invD[m_links[i].m_dofOffset * m_links[i].m_dofOffset];
1512
1513 for (int dof = 0; dof < m_links[i].m_dofCount; ++dof)
1514 {
1515 invD_times_Y[dof] = 0.f;
1516
1517 for (int dof2 = 0; dof2 < m_links[i].m_dofCount; ++dof2)
1518 {
1519 invD_times_Y[dof] += invDi[dof * m_links[i].m_dofCount + dof2] * Y[m_links[i].m_dofOffset + dof2];
1520 }
1521 }
1522
1523 // Zp += pXi * (Zi + hi*Yi/Di)
1524 spatForceVecTemps[0] = zeroAccSpatFrc[i + 1];
1525
1526 for (int dof = 0; dof < m_links[i].m_dofCount; ++dof)
1527 {
1528 const btSpatialForceVector &hDof = h[m_links[i].m_dofOffset + dof];
1529 //
1530 spatForceVecTemps[0] += hDof * invD_times_Y[dof];
1531 }
1532
1533 fromParent.transformInverse(spatForceVecTemps[0], spatForceVecTemps[1]);
1534
1535 zeroAccSpatFrc[parent + 1] += spatForceVecTemps[1];
1536 }
1537
1538 // ptr to the joint accel part of the output
1539 btScalar *joint_accel = output + 6;
1540
1541 // Second 'upward' loop
1542 // (part of TreeForwardDynamics in Mirtich)
1543
1545 {
1546 spatAcc[0].setZero();
1547 }
1548 else
1549 {
1550 solveImatrix(zeroAccSpatFrc[0], result);
1551 spatAcc[0] = -result;
1552 }
1553
1554 // now do the loop over the m_links
1555 for (int i = 0; i < num_links; ++i)
1556 {
1558 continue;
1559 const int parent = m_links[i].m_parent;
1560 fromParent.m_rotMat = rot_from_parent[i + 1];
1561 fromParent.m_trnVec = m_links[i].m_cachedRVector;
1562
1563 fromParent.transform(spatAcc[parent + 1], spatAcc[i + 1]);
1564
1565 for (int dof = 0; dof < m_links[i].m_dofCount; ++dof)
1566 {
1567 const btSpatialForceVector &hDof = h[m_links[i].m_dofOffset + dof];
1568 //
1569 Y_minus_hT_a[dof] = Y[m_links[i].m_dofOffset + dof] - spatAcc[i + 1].dot(hDof);
1570 }
1571
1572 const btScalar *invDi = &invD[m_links[i].m_dofOffset * m_links[i].m_dofOffset];
1573 mulMatrix(const_cast<btScalar *>(invDi), Y_minus_hT_a, m_links[i].m_dofCount, m_links[i].m_dofCount, m_links[i].m_dofCount, 1, &joint_accel[m_links[i].m_dofOffset]);
1574
1575 for (int dof = 0; dof < m_links[i].m_dofCount; ++dof)
1576 spatAcc[i + 1] += m_links[i].m_axes[dof] * joint_accel[m_links[i].m_dofOffset + dof];
1577 }
1578
1579 // transform base accelerations back to the world frame.
1580 btVector3 omegadot_out;
1581 omegadot_out = rot_from_parent[0].transpose() * spatAcc[0].getAngular();
1582 output[0] = omegadot_out[0];
1583 output[1] = omegadot_out[1];
1584 output[2] = omegadot_out[2];
1585
1586 btVector3 vdot_out;
1587 vdot_out = rot_from_parent[0].transpose() * spatAcc[0].getLinear();
1588 output[3] = vdot_out[0];
1589 output[4] = vdot_out[1];
1590 output[5] = vdot_out[2];
1591
1593 //printf("delta = [");
1594 //for(int dof = 0; dof < getNumDofs() + 6; ++dof)
1595 // printf("%.2f ", output[dof]);
1596 //printf("]\n");
1598}
1600{
1601 int num_links = getNumLinks();
1602 if(!isBaseKinematic())
1603 {
1604 // step position by adding dt * velocity
1605 //btVector3 v = getBaseVel();
1606 //m_basePos += dt * v;
1607 //
1608 btScalar *pBasePos;
1609 btScalar *pBaseVel = &m_realBuf[3]; //note: the !pqd case assumes m_realBuf holds with base velocity at 3,4,5 (should be wrapped for safety)
1610
1611 // reset to current position
1612 for (int i = 0; i < 3; ++i)
1613 {
1615 }
1616 pBasePos = m_basePos_interpolate;
1617
1618 pBasePos[0] += dt * pBaseVel[0];
1619 pBasePos[1] += dt * pBaseVel[1];
1620 pBasePos[2] += dt * pBaseVel[2];
1621 }
1622
1624 //local functor for quaternion integration (to avoid error prone redundancy)
1625 struct
1626 {
1627 //"exponential map" based on btTransformUtil::integrateTransform(..)
1628 void operator()(const btVector3 &omega, btQuaternion &quat, bool baseBody, btScalar dt)
1629 {
1630 //baseBody => quat is alias and omega is global coor
1632
1633 btVector3 axis;
1634 btVector3 angvel;
1635
1636 if (!baseBody)
1637 angvel = quatRotate(quat, omega); //if quat is not m_baseQuat, it is alibi => ok
1638 else
1639 angvel = omega;
1640
1641 btScalar fAngle = angvel.length();
1642 //limit the angular motion
1643 if (fAngle * dt > ANGULAR_MOTION_THRESHOLD)
1644 {
1645 fAngle = btScalar(0.5) * SIMD_HALF_PI / dt;
1646 }
1647
1648 if (fAngle < btScalar(0.001))
1649 {
1650 // use Taylor's expansions of sync function
1651 axis = angvel * (btScalar(0.5) * dt - (dt * dt * dt) * (btScalar(0.020833333333)) * fAngle * fAngle);
1652 }
1653 else
1654 {
1655 // sync(fAngle) = sin(c*fAngle)/t
1656 axis = angvel * (btSin(btScalar(0.5) * fAngle * dt) / fAngle);
1657 }
1658
1659 if (!baseBody)
1660 quat = btQuaternion(axis.x(), axis.y(), axis.z(), btCos(fAngle * dt * btScalar(0.5))) * quat;
1661 else
1662 quat = quat * btQuaternion(-axis.x(), -axis.y(), -axis.z(), btCos(fAngle * dt * btScalar(0.5)));
1663 //equivalent to: quat = (btQuaternion(axis.x(),axis.y(),axis.z(),btCos( fAngle*dt*btScalar(0.5) )) * quat.inverse()).inverse();
1664
1665 quat.normalize();
1666 }
1667 } pQuatUpdateFun;
1669
1670 //pQuatUpdateFun(getBaseOmega(), m_baseQuat, true, dt);
1671 //
1672 if(!isBaseKinematic())
1673 {
1674 btScalar *pBaseQuat;
1675
1676 // reset to current orientation
1677 for (int i = 0; i < 4; ++i)
1678 {
1680 }
1681 pBaseQuat = m_baseQuat_interpolate;
1682
1683 btScalar *pBaseOmega = &m_realBuf[0]; //note: the !pqd case assumes m_realBuf starts with base omega (should be wrapped for safety)
1684 //
1685 btQuaternion baseQuat;
1686 baseQuat.setValue(pBaseQuat[0], pBaseQuat[1], pBaseQuat[2], pBaseQuat[3]);
1687 btVector3 baseOmega;
1688 baseOmega.setValue(pBaseOmega[0], pBaseOmega[1], pBaseOmega[2]);
1689 pQuatUpdateFun(baseOmega, baseQuat, true, dt);
1690 pBaseQuat[0] = baseQuat.x();
1691 pBaseQuat[1] = baseQuat.y();
1692 pBaseQuat[2] = baseQuat.z();
1693 pBaseQuat[3] = baseQuat.w();
1694 }
1695
1696 // Finally we can update m_jointPos for each of the m_links
1697 for (int i = 0; i < num_links; ++i)
1698 {
1699 btScalar *pJointPos;
1700 pJointPos = &m_links[i].m_jointPos_interpolate[0];
1701
1702 if (m_links[i].m_collider && m_links[i].m_collider->isStaticOrKinematic())
1703 {
1704 switch (m_links[i].m_jointType)
1705 {
1708 {
1709 pJointPos[0] = m_links[i].m_jointPos[0];
1710 break;
1711 }
1713 {
1714 for (int j = 0; j < 4; ++j)
1715 {
1716 pJointPos[j] = m_links[i].m_jointPos[j];
1717 }
1718 break;
1719 }
1721 {
1722 for (int j = 0; j < 3; ++j)
1723 {
1724 pJointPos[j] = m_links[i].m_jointPos[j];
1725 }
1726 break;
1727 }
1728 default:
1729 break;
1730 }
1731 }
1732 else
1733 {
1734 btScalar *pJointVel = getJointVelMultiDof(i);
1735
1736 switch (m_links[i].m_jointType)
1737 {
1740 {
1741 //reset to current pos
1742 pJointPos[0] = m_links[i].m_jointPos[0];
1743 btScalar jointVel = pJointVel[0];
1744 pJointPos[0] += dt * jointVel;
1745 break;
1746 }
1748 {
1749 //reset to current pos
1750
1751 for (int j = 0; j < 4; ++j)
1752 {
1753 pJointPos[j] = m_links[i].m_jointPos[j];
1754 }
1755
1756 btVector3 jointVel;
1757 jointVel.setValue(pJointVel[0], pJointVel[1], pJointVel[2]);
1758 btQuaternion jointOri;
1759 jointOri.setValue(pJointPos[0], pJointPos[1], pJointPos[2], pJointPos[3]);
1760 pQuatUpdateFun(jointVel, jointOri, false, dt);
1761 pJointPos[0] = jointOri.x();
1762 pJointPos[1] = jointOri.y();
1763 pJointPos[2] = jointOri.z();
1764 pJointPos[3] = jointOri.w();
1765 break;
1766 }
1768 {
1769 for (int j = 0; j < 3; ++j)
1770 {
1771 pJointPos[j] = m_links[i].m_jointPos[j];
1772 }
1773 pJointPos[0] += dt * getJointVelMultiDof(i)[0];
1774
1775 btVector3 q0_coors_qd1qd2 = getJointVelMultiDof(i)[1] * m_links[i].getAxisBottom(1) + getJointVelMultiDof(i)[2] * m_links[i].getAxisBottom(2);
1776 btVector3 no_q0_coors_qd1qd2 = quatRotate(btQuaternion(m_links[i].getAxisTop(0), pJointPos[0]), q0_coors_qd1qd2);
1777 pJointPos[1] += m_links[i].getAxisBottom(1).dot(no_q0_coors_qd1qd2) * dt;
1778 pJointPos[2] += m_links[i].getAxisBottom(2).dot(no_q0_coors_qd1qd2) * dt;
1779 break;
1780 }
1781 default:
1782 {
1783 }
1784 }
1785 }
1786
1787 m_links[i].updateInterpolationCacheMultiDof();
1788 }
1789}
1790
1792{
1793 int num_links = getNumLinks();
1794 if(!isBaseKinematic())
1795 {
1796 // step position by adding dt * velocity
1797 //btVector3 v = getBaseVel();
1798 //m_basePos += dt * v;
1799 //
1800 btScalar *pBasePos = (pq ? &pq[4] : m_basePos);
1801 btScalar *pBaseVel = (pqd ? &pqd[3] : &m_realBuf[3]); //note: the !pqd case assumes m_realBuf holds with base velocity at 3,4,5 (should be wrapped for safety)
1802
1803 pBasePos[0] += dt * pBaseVel[0];
1804 pBasePos[1] += dt * pBaseVel[1];
1805 pBasePos[2] += dt * pBaseVel[2];
1806 }
1807
1809 //local functor for quaternion integration (to avoid error prone redundancy)
1810 struct
1811 {
1812 //"exponential map" based on btTransformUtil::integrateTransform(..)
1813 void operator()(const btVector3 &omega, btQuaternion &quat, bool baseBody, btScalar dt)
1814 {
1815 //baseBody => quat is alias and omega is global coor
1817
1818 btVector3 axis;
1819 btVector3 angvel;
1820
1821 if (!baseBody)
1822 angvel = quatRotate(quat, omega); //if quat is not m_baseQuat, it is alibi => ok
1823 else
1824 angvel = omega;
1825
1826 btScalar fAngle = angvel.length();
1827 //limit the angular motion
1828 if (fAngle * dt > ANGULAR_MOTION_THRESHOLD)
1829 {
1830 fAngle = btScalar(0.5) * SIMD_HALF_PI / dt;
1831 }
1832
1833 if (fAngle < btScalar(0.001))
1834 {
1835 // use Taylor's expansions of sync function
1836 axis = angvel * (btScalar(0.5) * dt - (dt * dt * dt) * (btScalar(0.020833333333)) * fAngle * fAngle);
1837 }
1838 else
1839 {
1840 // sync(fAngle) = sin(c*fAngle)/t
1841 axis = angvel * (btSin(btScalar(0.5) * fAngle * dt) / fAngle);
1842 }
1843
1844 if (!baseBody)
1845 quat = btQuaternion(axis.x(), axis.y(), axis.z(), btCos(fAngle * dt * btScalar(0.5))) * quat;
1846 else
1847 quat = quat * btQuaternion(-axis.x(), -axis.y(), -axis.z(), btCos(fAngle * dt * btScalar(0.5)));
1848 //equivalent to: quat = (btQuaternion(axis.x(),axis.y(),axis.z(),btCos( fAngle*dt*btScalar(0.5) )) * quat.inverse()).inverse();
1849
1850 quat.normalize();
1851 }
1852 } pQuatUpdateFun;
1854
1855 //pQuatUpdateFun(getBaseOmega(), m_baseQuat, true, dt);
1856 //
1857 if(!isBaseKinematic())
1858 {
1859 btScalar *pBaseQuat = pq ? pq : m_baseQuat;
1860 btScalar *pBaseOmega = pqd ? pqd : &m_realBuf[0]; //note: the !pqd case assumes m_realBuf starts with base omega (should be wrapped for safety)
1861 //
1862 btQuaternion baseQuat;
1863 baseQuat.setValue(pBaseQuat[0], pBaseQuat[1], pBaseQuat[2], pBaseQuat[3]);
1864 btVector3 baseOmega;
1865 baseOmega.setValue(pBaseOmega[0], pBaseOmega[1], pBaseOmega[2]);
1866 pQuatUpdateFun(baseOmega, baseQuat, true, dt);
1867 pBaseQuat[0] = baseQuat.x();
1868 pBaseQuat[1] = baseQuat.y();
1869 pBaseQuat[2] = baseQuat.z();
1870 pBaseQuat[3] = baseQuat.w();
1871
1872 //printf("pBaseOmega = %.4f %.4f %.4f\n", pBaseOmega->x(), pBaseOmega->y(), pBaseOmega->z());
1873 //printf("pBaseVel = %.4f %.4f %.4f\n", pBaseVel->x(), pBaseVel->y(), pBaseVel->z());
1874 //printf("baseQuat = %.4f %.4f %.4f %.4f\n", pBaseQuat->x(), pBaseQuat->y(), pBaseQuat->z(), pBaseQuat->w());
1875 }
1876
1877 if (pq)
1878 pq += 7;
1879 if (pqd)
1880 pqd += 6;
1881
1882 // Finally we can update m_jointPos for each of the m_links
1883 for (int i = 0; i < num_links; ++i)
1884 {
1885 if (!(m_links[i].m_collider && m_links[i].m_collider->isStaticOrKinematic()))
1886 {
1887 btScalar *pJointPos;
1888 pJointPos= (pq ? pq : &m_links[i].m_jointPos[0]);
1889
1890 btScalar *pJointVel = (pqd ? pqd : getJointVelMultiDof(i));
1891
1892 switch (m_links[i].m_jointType)
1893 {
1896 {
1897 //reset to current pos
1898 btScalar jointVel = pJointVel[0];
1899 pJointPos[0] += dt * jointVel;
1900 break;
1901 }
1903 {
1904 //reset to current pos
1905 btVector3 jointVel;
1906 jointVel.setValue(pJointVel[0], pJointVel[1], pJointVel[2]);
1907 btQuaternion jointOri;
1908 jointOri.setValue(pJointPos[0], pJointPos[1], pJointPos[2], pJointPos[3]);
1909 pQuatUpdateFun(jointVel, jointOri, false, dt);
1910 pJointPos[0] = jointOri.x();
1911 pJointPos[1] = jointOri.y();
1912 pJointPos[2] = jointOri.z();
1913 pJointPos[3] = jointOri.w();
1914 break;
1915 }
1917 {
1918 pJointPos[0] += dt * getJointVelMultiDof(i)[0];
1919
1920 btVector3 q0_coors_qd1qd2 = getJointVelMultiDof(i)[1] * m_links[i].getAxisBottom(1) + getJointVelMultiDof(i)[2] * m_links[i].getAxisBottom(2);
1921 btVector3 no_q0_coors_qd1qd2 = quatRotate(btQuaternion(m_links[i].getAxisTop(0), pJointPos[0]), q0_coors_qd1qd2);
1922 pJointPos[1] += m_links[i].getAxisBottom(1).dot(no_q0_coors_qd1qd2) * dt;
1923 pJointPos[2] += m_links[i].getAxisBottom(2).dot(no_q0_coors_qd1qd2) * dt;
1924
1925 break;
1926 }
1927 default:
1928 {
1929 }
1930 }
1931 }
1932
1933 m_links[i].updateCacheMultiDof(pq);
1934
1935 if (pq)
1936 pq += m_links[i].m_posVarCount;
1937 if (pqd)
1938 pqd += m_links[i].m_dofCount;
1939 }
1940}
1941
1943 const btVector3 &contact_point,
1944 const btVector3 &normal_ang,
1945 const btVector3 &normal_lin,
1946 btScalar *jac,
1949 btAlignedObjectArray<btMatrix3x3> &scratch_m) const
1950{
1951 // temporary space
1952 int num_links = getNumLinks();
1953 int m_dofCount = getNumDofs();
1954 scratch_v.resize(3 * num_links + 3); //(num_links + base) offsets + (num_links + base) normals_lin + (num_links + base) normals_ang
1955 scratch_m.resize(num_links + 1);
1956
1957 btVector3 *v_ptr = &scratch_v[0];
1958 btVector3 *p_minus_com_local = v_ptr;
1959 v_ptr += num_links + 1;
1960 btVector3 *n_local_lin = v_ptr;
1961 v_ptr += num_links + 1;
1962 btVector3 *n_local_ang = v_ptr;
1963 v_ptr += num_links + 1;
1964 btAssert(v_ptr - &scratch_v[0] == scratch_v.size());
1965
1966 //scratch_r.resize(m_dofCount);
1967 //btScalar *results = m_dofCount > 0 ? &scratch_r[0] : 0;
1968
1969 scratch_r1.resize(m_dofCount+num_links);
1970 btScalar * results = m_dofCount > 0 ? &scratch_r1[0] : 0;
1971 btScalar* links = num_links? &scratch_r1[m_dofCount] : 0;
1972 int numLinksChildToRoot=0;
1973 int l = link;
1974 while (l != -1)
1975 {
1976 links[numLinksChildToRoot++]=l;
1977 l = m_links[l].m_parent;
1978 }
1979
1980 btMatrix3x3 *rot_from_world = &scratch_m[0];
1981
1982 const btVector3 p_minus_com_world = contact_point - m_basePos;
1983 const btVector3 &normal_lin_world = normal_lin; //convenience
1984 const btVector3 &normal_ang_world = normal_ang;
1985
1986 rot_from_world[0] = btMatrix3x3(m_baseQuat);
1987
1988 // omega coeffients first.
1989 btVector3 omega_coeffs_world;
1990 omega_coeffs_world = p_minus_com_world.cross(normal_lin_world);
1991 jac[0] = omega_coeffs_world[0] + normal_ang_world[0];
1992 jac[1] = omega_coeffs_world[1] + normal_ang_world[1];
1993 jac[2] = omega_coeffs_world[2] + normal_ang_world[2];
1994 // then v coefficients
1995 jac[3] = normal_lin_world[0];
1996 jac[4] = normal_lin_world[1];
1997 jac[5] = normal_lin_world[2];
1998
1999 //create link-local versions of p_minus_com and normal
2000 p_minus_com_local[0] = rot_from_world[0] * p_minus_com_world;
2001 n_local_lin[0] = rot_from_world[0] * normal_lin_world;
2002 n_local_ang[0] = rot_from_world[0] * normal_ang_world;
2003
2004 // Set remaining jac values to zero for now.
2005 for (int i = 6; i < 6 + m_dofCount; ++i)
2006 {
2007 jac[i] = 0;
2008 }
2009
2010 // Qdot coefficients, if necessary.
2011 if (num_links > 0 && link > -1)
2012 {
2013 // TODO: (Also, we are making 3 separate calls to this function, for the normal & the 2 friction directions,
2014 // which is resulting in repeated work being done...)
2015
2016 // calculate required normals & positions in the local frames.
2017 for (int a = 0; a < numLinksChildToRoot; a++)
2018 {
2019 int i = links[numLinksChildToRoot-1-a];
2020 // transform to local frame
2021 const int parent = m_links[i].m_parent;
2022 const btMatrix3x3 mtx(m_links[i].m_cachedRotParentToThis);
2023 rot_from_world[i + 1] = mtx * rot_from_world[parent + 1];
2024
2025 n_local_lin[i + 1] = mtx * n_local_lin[parent + 1];
2026 n_local_ang[i + 1] = mtx * n_local_ang[parent + 1];
2027 p_minus_com_local[i + 1] = mtx * p_minus_com_local[parent + 1] - m_links[i].m_cachedRVector;
2028
2029 // calculate the jacobian entry
2030 switch (m_links[i].m_jointType)
2031 {
2033 {
2034 results[m_links[i].m_dofOffset] = n_local_lin[i + 1].dot(m_links[i].getAxisTop(0).cross(p_minus_com_local[i + 1]) + m_links[i].getAxisBottom(0));
2035 results[m_links[i].m_dofOffset] += n_local_ang[i + 1].dot(m_links[i].getAxisTop(0));
2036 break;
2037 }
2039 {
2040 results[m_links[i].m_dofOffset] = n_local_lin[i + 1].dot(m_links[i].getAxisBottom(0));
2041 break;
2042 }
2044 {
2045 results[m_links[i].m_dofOffset + 0] = n_local_lin[i + 1].dot(m_links[i].getAxisTop(0).cross(p_minus_com_local[i + 1]) + m_links[i].getAxisBottom(0));
2046 results[m_links[i].m_dofOffset + 1] = n_local_lin[i + 1].dot(m_links[i].getAxisTop(1).cross(p_minus_com_local[i + 1]) + m_links[i].getAxisBottom(1));
2047 results[m_links[i].m_dofOffset + 2] = n_local_lin[i + 1].dot(m_links[i].getAxisTop(2).cross(p_minus_com_local[i + 1]) + m_links[i].getAxisBottom(2));
2048
2049 results[m_links[i].m_dofOffset + 0] += n_local_ang[i + 1].dot(m_links[i].getAxisTop(0));
2050 results[m_links[i].m_dofOffset + 1] += n_local_ang[i + 1].dot(m_links[i].getAxisTop(1));
2051 results[m_links[i].m_dofOffset + 2] += n_local_ang[i + 1].dot(m_links[i].getAxisTop(2));
2052
2053 break;
2054 }
2056 {
2057 results[m_links[i].m_dofOffset + 0] = n_local_lin[i + 1].dot(m_links[i].getAxisTop(0).cross(p_minus_com_local[i + 1])); // + m_links[i].getAxisBottom(0));
2058 results[m_links[i].m_dofOffset + 1] = n_local_lin[i + 1].dot(m_links[i].getAxisBottom(1));
2059 results[m_links[i].m_dofOffset + 2] = n_local_lin[i + 1].dot(m_links[i].getAxisBottom(2));
2060
2061 break;
2062 }
2063 default:
2064 {
2065 }
2066 }
2067 }
2068
2069 // Now copy through to output.
2070 //printf("jac[%d] = ", link);
2071 while (link != -1)
2072 {
2073 for (int dof = 0; dof < m_links[link].m_dofCount; ++dof)
2074 {
2075 jac[6 + m_links[link].m_dofOffset + dof] = results[m_links[link].m_dofOffset + dof];
2076 //printf("%.2f\t", jac[6 + m_links[link].m_dofOffset + dof]);
2077 }
2078
2079 link = m_links[link].m_parent;
2080 }
2081 //printf("]\n");
2082 }
2083}
2084
2086{
2087 m_sleepTimer = 0;
2088 m_awake = true;
2089}
2090
2092{
2093 m_awake = false;
2094}
2095
2097{
2098 extern bool gDisableDeactivation;
2100 {
2101 m_awake = true;
2102 m_sleepTimer = 0;
2103 return;
2104 }
2105
2106
2107
2108 // motion is computed as omega^2 + v^2 + (sum of squares of joint velocities)
2109 btScalar motion = 0;
2110 {
2111 for (int i = 0; i < 6 + m_dofCount; ++i)
2112 motion += m_realBuf[i] * m_realBuf[i];
2113 }
2114
2115 if (motion < m_sleepEpsilon)
2116 {
2117 m_sleepTimer += timestep;
2119 {
2120 goToSleep();
2121 }
2122 }
2123 else
2124 {
2125 m_sleepTimer = 0;
2126 if (m_canWakeup)
2127 {
2128 if (!m_awake)
2129 wakeUp();
2130 }
2131 }
2132}
2133
2135{
2136 int num_links = getNumLinks();
2137
2138 // Cached 3x3 rotation matrices from parent frame to this frame.
2139 btMatrix3x3 *rot_from_parent = (btMatrix3x3 *)&m_matrixBuf[0];
2140
2141 rot_from_parent[0] = btMatrix3x3(m_baseQuat); //m_baseQuat assumed to be alias!?
2142
2143 for (int i = 0; i < num_links; ++i)
2144 {
2145 rot_from_parent[i + 1] = btMatrix3x3(m_links[i].m_cachedRotParentToThis);
2146 }
2147
2148 int nLinks = getNumLinks();
2150 world_to_local.resize(nLinks + 1);
2151 local_origin.resize(nLinks + 1);
2152
2153 world_to_local[0] = getWorldToBaseRot();
2154 local_origin[0] = getBasePos();
2155
2156 for (int k = 0; k < getNumLinks(); k++)
2157 {
2158 const int parent = getParent(k);
2159 world_to_local[k + 1] = getParentToLocalRot(k) * world_to_local[parent + 1];
2160 local_origin[k + 1] = local_origin[parent + 1] + (quatRotate(world_to_local[k + 1].inverse(), getRVector(k)));
2161 }
2162
2163 for (int link = 0; link < getNumLinks(); link++)
2164 {
2165 int index = link + 1;
2166
2167 btVector3 posr = local_origin[index];
2168 btScalar quat[4] = {-world_to_local[index].x(), -world_to_local[index].y(), -world_to_local[index].z(), world_to_local[index].w()};
2169 btTransform tr;
2170 tr.setIdentity();
2171 tr.setOrigin(posr);
2172 tr.setRotation(btQuaternion(quat[0], quat[1], quat[2], quat[3]));
2174 }
2175}
2176
2178{
2179 world_to_local.resize(getNumLinks() + 1);
2180 local_origin.resize(getNumLinks() + 1);
2181
2182 world_to_local[0] = getWorldToBaseRot();
2183 local_origin[0] = getBasePos();
2184
2185 if (getBaseCollider())
2186 {
2187 btVector3 posr = local_origin[0];
2188 // float pos[4]={posr.x(),posr.y(),posr.z(),1};
2189 btScalar quat[4] = {-world_to_local[0].x(), -world_to_local[0].y(), -world_to_local[0].z(), world_to_local[0].w()};
2190 btTransform tr;
2191 tr.setIdentity();
2192 tr.setOrigin(posr);
2193 tr.setRotation(btQuaternion(quat[0], quat[1], quat[2], quat[3]));
2194
2197 }
2198
2199 for (int k = 0; k < getNumLinks(); k++)
2200 {
2201 const int parent = getParent(k);
2202 world_to_local[k + 1] = getParentToLocalRot(k) * world_to_local[parent + 1];
2203 local_origin[k + 1] = local_origin[parent + 1] + (quatRotate(world_to_local[k + 1].inverse(), getRVector(k)));
2204 }
2205
2206 for (int m = 0; m < getNumLinks(); m++)
2207 {
2209 if (col)
2210 {
2211 int link = col->m_link;
2212 btAssert(link == m);
2213
2214 int index = link + 1;
2215
2216 btVector3 posr = local_origin[index];
2217 // float pos[4]={posr.x(),posr.y(),posr.z(),1};
2218 btScalar quat[4] = {-world_to_local[index].x(), -world_to_local[index].y(), -world_to_local[index].z(), world_to_local[index].w()};
2219 btTransform tr;
2220 tr.setIdentity();
2221 tr.setOrigin(posr);
2222 tr.setRotation(btQuaternion(quat[0], quat[1], quat[2], quat[3]));
2223
2224 col->setWorldTransform(tr);
2226 }
2227 }
2228}
2229
2231{
2232 world_to_local.resize(getNumLinks() + 1);
2233 local_origin.resize(getNumLinks() + 1);
2234
2235 if(isBaseKinematic()){
2236 world_to_local[0] = getWorldToBaseRot();
2237 local_origin[0] = getBasePos();
2238 }
2239 else
2240 {
2241 world_to_local[0] = getInterpolateWorldToBaseRot();
2242 local_origin[0] = getInterpolateBasePos();
2243 }
2244
2245 if (getBaseCollider())
2246 {
2247 btVector3 posr = local_origin[0];
2248 // float pos[4]={posr.x(),posr.y(),posr.z(),1};
2249 btScalar quat[4] = {-world_to_local[0].x(), -world_to_local[0].y(), -world_to_local[0].z(), world_to_local[0].w()};
2250 btTransform tr;
2251 tr.setIdentity();
2252 tr.setOrigin(posr);
2253 tr.setRotation(btQuaternion(quat[0], quat[1], quat[2], quat[3]));
2254
2256 }
2257
2258 for (int k = 0; k < getNumLinks(); k++)
2259 {
2260 const int parent = getParent(k);
2261 world_to_local[k + 1] = getInterpolateParentToLocalRot(k) * world_to_local[parent + 1];
2262 local_origin[k + 1] = local_origin[parent + 1] + (quatRotate(world_to_local[k + 1].inverse(), getInterpolateRVector(k)));
2263 }
2264
2265 for (int m = 0; m < getNumLinks(); m++)
2266 {
2268 if (col)
2269 {
2270 int link = col->m_link;
2271 btAssert(link == m);
2272
2273 int index = link + 1;
2274
2275 btVector3 posr = local_origin[index];
2276 // float pos[4]={posr.x(),posr.y(),posr.z(),1};
2277 btScalar quat[4] = {-world_to_local[index].x(), -world_to_local[index].y(), -world_to_local[index].z(), world_to_local[index].w()};
2278 btTransform tr;
2279 tr.setIdentity();
2280 tr.setOrigin(posr);
2281 tr.setRotation(btQuaternion(quat[0], quat[1], quat[2], quat[3]));
2282
2284 }
2285 }
2286}
2287
2289{
2290 int sz = sizeof(btMultiBodyData);
2291 return sz;
2292}
2293
2295const char *btMultiBody::serialize(void *dataBuffer, class btSerializer *serializer) const
2296{
2297 btMultiBodyData *mbd = (btMultiBodyData *)dataBuffer;
2298 getBasePos().serialize(mbd->m_baseWorldPosition);
2299 getWorldToBaseRot().inverse().serialize(mbd->m_baseWorldOrientation);
2300 getBaseVel().serialize(mbd->m_baseLinearVelocity);
2301 getBaseOmega().serialize(mbd->m_baseAngularVelocity);
2302
2303 mbd->m_baseMass = this->getBaseMass();
2304 getBaseInertia().serialize(mbd->m_baseInertia);
2305 {
2306 char *name = (char *)serializer->findNameForPointer(m_baseName);
2307 mbd->m_baseName = (char *)serializer->getUniquePointer(name);
2308 if (mbd->m_baseName)
2309 {
2310 serializer->serializeName(name);
2311 }
2312 }
2313 mbd->m_numLinks = this->getNumLinks();
2314 if (mbd->m_numLinks)
2315 {
2316 int sz = sizeof(btMultiBodyLinkData);
2317 int numElem = mbd->m_numLinks;
2318 btChunk *chunk = serializer->allocate(sz, numElem);
2320 for (int i = 0; i < numElem; i++, memPtr++)
2321 {
2322 memPtr->m_jointType = getLink(i).m_jointType;
2323 memPtr->m_dofCount = getLink(i).m_dofCount;
2324 memPtr->m_posVarCount = getLink(i).m_posVarCount;
2325
2326 getLink(i).m_inertiaLocal.serialize(memPtr->m_linkInertia);
2327
2328 getLink(i).m_absFrameTotVelocity.m_topVec.serialize(memPtr->m_absFrameTotVelocityTop);
2329 getLink(i).m_absFrameTotVelocity.m_bottomVec.serialize(memPtr->m_absFrameTotVelocityBottom);
2330 getLink(i).m_absFrameLocVelocity.m_topVec.serialize(memPtr->m_absFrameLocVelocityTop);
2331 getLink(i).m_absFrameLocVelocity.m_bottomVec.serialize(memPtr->m_absFrameLocVelocityBottom);
2332
2333 memPtr->m_linkMass = getLink(i).m_mass;
2334 memPtr->m_parentIndex = getLink(i).m_parent;
2335 memPtr->m_jointDamping = getLink(i).m_jointDamping;
2336 memPtr->m_jointFriction = getLink(i).m_jointFriction;
2337 memPtr->m_jointLowerLimit = getLink(i).m_jointLowerLimit;
2338 memPtr->m_jointUpperLimit = getLink(i).m_jointUpperLimit;
2339 memPtr->m_jointMaxForce = getLink(i).m_jointMaxForce;
2340 memPtr->m_jointMaxVelocity = getLink(i).m_jointMaxVelocity;
2341
2342 getLink(i).m_eVector.serialize(memPtr->m_parentComToThisPivotOffset);
2343 getLink(i).m_dVector.serialize(memPtr->m_thisPivotToThisComOffset);
2344 getLink(i).m_zeroRotParentToThis.serialize(memPtr->m_zeroRotParentToThis);
2345 btAssert(memPtr->m_dofCount <= 3);
2346 for (int dof = 0; dof < getLink(i).m_dofCount; dof++)
2347 {
2348 getLink(i).getAxisBottom(dof).serialize(memPtr->m_jointAxisBottom[dof]);
2349 getLink(i).getAxisTop(dof).serialize(memPtr->m_jointAxisTop[dof]);
2350
2351 memPtr->m_jointTorque[dof] = getLink(i).m_jointTorque[dof];
2352 memPtr->m_jointVel[dof] = getJointVelMultiDof(i)[dof];
2353 }
2354 int numPosVar = getLink(i).m_posVarCount;
2355 for (int posvar = 0; posvar < numPosVar; posvar++)
2356 {
2357 memPtr->m_jointPos[posvar] = getLink(i).m_jointPos[posvar];
2358 }
2359
2360 {
2361 char *name = (char *)serializer->findNameForPointer(m_links[i].m_linkName);
2362 memPtr->m_linkName = (char *)serializer->getUniquePointer(name);
2363 if (memPtr->m_linkName)
2364 {
2365 serializer->serializeName(name);
2366 }
2367 }
2368 {
2369 char *name = (char *)serializer->findNameForPointer(m_links[i].m_jointName);
2370 memPtr->m_jointName = (char *)serializer->getUniquePointer(name);
2371 if (memPtr->m_jointName)
2372 {
2373 serializer->serializeName(name);
2374 }
2375 }
2376 memPtr->m_linkCollider = (btCollisionObjectData *)serializer->getUniquePointer(getLink(i).m_collider);
2377 }
2378 serializer->finalizeChunk(chunk, btMultiBodyLinkDataName, BT_ARRAY_CODE, (void *)&m_links[0]);
2379 }
2380 mbd->m_links = mbd->m_numLinks ? (btMultiBodyLinkData *)serializer->getUniquePointer((void *)&m_links[0]) : 0;
2381
2382 // Fill padding with zeros to appease msan.
2383#ifdef BT_USE_DOUBLE_PRECISION
2384 memset(mbd->m_padding, 0, sizeof(mbd->m_padding));
2385#endif
2386
2387 return btMultiBodyDataName;
2388}
2389
2391{
2392 //todo: clamp to some (user definable) safe minimum timestep, to limit maximum angular/linear velocities
2393 if (m_kinematic_calculate_velocity && timeStep != btScalar(0.))
2394 {
2395 btVector3 linearVelocity, angularVelocity;
2396 btTransformUtil::calculateVelocity(getInterpolateBaseWorldTransform(), getBaseWorldTransform(), timeStep, linearVelocity, angularVelocity);
2397 setBaseVel(linearVelocity);
2398 setBaseOmega(angularVelocity);
2400 }
2401}
2402
2403void btMultiBody::setLinkDynamicType(const int i, int type)
2404{
2405 if (i == -1)
2406 {
2407 setBaseDynamicType(type);
2408 }
2409 else if (i >= 0 && i < getNumLinks())
2410 {
2411 if (m_links[i].m_collider)
2412 {
2413 m_links[i].m_collider->setDynamicType(type);
2414 }
2415 }
2416}
2417
2419{
2420 if (i == -1)
2421 {
2422 return isBaseStaticOrKinematic();
2423 }
2424 else
2425 {
2426 if (m_links[i].m_collider)
2427 return m_links[i].m_collider->isStaticOrKinematic();
2428 }
2429 return false;
2430}
2431
2432bool btMultiBody::isLinkKinematic(const int i) const
2433{
2434 if (i == -1)
2435 {
2436 return isBaseKinematic();
2437 }
2438 else
2439 {
2440 if (m_links[i].m_collider)
2441 return m_links[i].m_collider->isKinematic();
2442 }
2443 return false;
2444}
2445
2447{
2448 int link = i;
2449 while (link != -1) {
2450 if (!isLinkStaticOrKinematic(link))
2451 return false;
2452 link = m_links[link].m_parent;
2453 }
2454 return isBaseStaticOrKinematic();
2455}
2456
2458{
2459 int link = i;
2460 while (link != -1) {
2461 if (!isLinkKinematic(link))
2462 return false;
2463 link = m_links[link].m_parent;
2464 }
2465 return isBaseKinematic();
2466}
#define btCollisionObjectData
#define output
btMatrix3x3 outerProduct(const btVector3 &v0, const btVector3 &v1)
#define btMultiBodyDataName
Definition btMultiBody.h:41
#define btMultiBodyData
serialization data, don't change them if you are not familiar with the details of the serialization m...
Definition btMultiBody.h:40
#define btMultiBodyLinkData
Definition btMultiBody.h:42
#define btMultiBodyLinkDataName
Definition btMultiBody.h:43
btQuaternion inverse(const btQuaternion &q)
Return the inverse of a quaternion.
btVector3 quatRotate(const btQuaternion &rotation, const btVector3 &v)
bool gDisableDeactivation
float btScalar
The btScalar type abstracts floating point numbers, to easily switch between double and single floati...
Definition btScalar.h:314
btScalar btSin(btScalar x)
Definition btScalar.h:499
#define SIMD_INFINITY
Definition btScalar.h:544
btScalar btCos(btScalar x)
Definition btScalar.h:498
#define SIMD_EPSILON
Definition btScalar.h:543
#define SIMD_HALF_PI
Definition btScalar.h:528
#define btAssert(x)
Definition btScalar.h:153
#define BT_ARRAY_CODE
void symmetricSpatialOuterProduct(const SpatialVectorType &a, const SpatialVectorType &b, btSymmetricSpatialDyad &out)
#define ANGULAR_MOTION_THRESHOLD
The btAlignedObjectArray template class uses a subset of the stl::vector interface for its methods It...
int size() const
return the number of elements in the array
void resize(int newsize, const T &fillData=T())
void * m_oldPtr
bool isStaticOrKinematicObject() const
void setCollisionFlags(int flags)
bool isStaticObject() const
void setWorldTransform(const btTransform &worldTrans)
bool isKinematicObject() const
int getCollisionFlags() const
void setInterpolationWorldTransform(const btTransform &trans)
The btMatrix3x3 class implements a 3x3 rotation matrix, to perform linear algebra in combination with...
Definition btMatrix3x3.h:50
btMatrix3x3 inverse() const
Return the inverse of the matrix.
btMatrix3x3 transpose() const
Return the transpose of the matrix.
btVector3 getColumn(int i) const
Get a column of the matrix as a vector.
void setValue(const btScalar &xx, const btScalar &xy, const btScalar &xz, const btScalar &yx, const btScalar &yy, const btScalar &yz, const btScalar &zx, const btScalar &zy, const btScalar &zz)
Set the values of the matrix explicitly (row major)
btScalar m_maxCoordinateVelocity
bool __posUpdated
btTransform getInterpolateBaseWorldTransform() const
void setupPrismatic(int i, btScalar mass, const btVector3 &inertia, int parent, const btQuaternion &rotParentToThis, const btVector3 &jointAxis, const btVector3 &parentComToThisPivotOffset, const btVector3 &thisPivotToThisComOffset, bool disableParentCollision)
bool m_useGyroTerm
const btVector3 & getInterpolateBasePos() const
void setJointVelMultiDof(int i, const double *qdot)
const btVector3 & getLinkTorque(int i) const
void updateCollisionObjectInterpolationWorldTransforms(btAlignedObjectArray< btQuaternion > &world_to_local, btAlignedObjectArray< btVector3 > &local_origin)
btAlignedObjectArray< btMultibodyLink > m_links
btAlignedObjectArray< btMatrix3x3 > m_matrixBuf
btMultiBodyLinkCollider * m_baseCollider
btMatrix3x3 localFrameToWorld(int i, const btMatrix3x3 &local_frame) const
const btVector3 & getBasePos() const
virtual const char * serialize(void *dataBuffer, class btSerializer *serializer) const
fills the dataBuffer and returns the struct name (and 0 on failure)
void finalizeMultiDof()
bool isLinkAndAllAncestorsKinematic(const int i) const
btVector3 m_basePos_interpolate
btVector3 m_baseInertia
btAlignedObjectArray< btVector3 > m_vectorBuf
btVector3 m_baseForce
const btQuaternion & getInterpolateParentToLocalRot(int i) const
btScalar m_maxAppliedImpulse
btVector3 worldDirToLocal(int i, const btVector3 &world_dir) const
btScalar getJointPos(int i) const
const btVector3 & getLinkInertia(int i) const
btScalar m_sleepTimeout
void setBaseDynamicType(int dynamicType)
btScalar * getJointPosMultiDof(int i)
btScalar m_angularDamping
btQuaternion m_baseQuat
void predictPositionsMultiDof(btScalar dt)
btVector3 m_basePos
void clearVelocities()
void * m_userObjectPointer
const char * m_baseName
void setBaseVel(const btVector3 &vel)
btMatrix3x3 m_cachedInertiaLowerRight
void setBaseOmega(const btVector3 &omega)
void computeAccelerationsArticulatedBodyAlgorithmMultiDof(btScalar dt, btAlignedObjectArray< btScalar > &scratch_r, btAlignedObjectArray< btVector3 > &scratch_v, btAlignedObjectArray< btMatrix3x3 > &scratch_m, bool isConstraintPass, bool jointFeedbackInWorldSpace, bool jointFeedbackInJointFrame)
int getNumLinks() const
btScalar m_baseMass
void addLinkConstraintForce(int i, const btVector3 &f)
bool m_hasSelfCollision
btAlignedObjectArray< btScalar > m_realBuf
btVector3 m_baseConstraintTorque
void stepPositionsMultiDof(btScalar dt, btScalar *pq=0, btScalar *pqd=0)
const btMultibodyLink & getLink(int index) const
const btVector3 & getRVector(int i) const
btVector3 getBaseOmega() const
void calcAccelerationDeltasMultiDof(const btScalar *force, btScalar *output, btAlignedObjectArray< btScalar > &scratch_r, btAlignedObjectArray< btVector3 > &scratch_v) const
stepVelocitiesMultiDof is deprecated, use computeAccelerationsArticulatedBodyAlgorithmMultiDof instea...
btVector3 worldPosToLocal(int i, const btVector3 &world_pos) const
void addLinkTorque(int i, const btVector3 &t)
void checkMotionAndSleepIfRequired(btScalar timestep)
btScalar * getJointTorqueMultiDof(int i)
btQuaternion m_baseQuat_interpolate
void solveImatrix(const btVector3 &rhs_top, const btVector3 &rhs_bot, btScalar result[6]) const
const btVector3 & getInterpolateRVector(int i) const
bool isBaseKinematic() const
btScalar m_sleepEpsilon
btScalar getLinkMass(int i) const
int getNumDofs() const
bool m_useGlobalVelocities
void addLinkForce(int i, const btVector3 &f)
void addJointTorque(int i, btScalar Q)
btMatrix3x3 m_cachedInertiaLowerLeft
void mulMatrix(const btScalar *pA, const btScalar *pB, int rowsA, int colsA, int rowsB, int colsB, btScalar *pC) const
void setInterpolateBaseWorldTransform(const btTransform &tr)
const btVector3 & getLinkForce(int i) const
int getParent(int link_num) const
void setJointPosMultiDof(int i, const double *q)
void updateCollisionObjectWorldTransforms(btAlignedObjectArray< btQuaternion > &world_to_local, btAlignedObjectArray< btVector3 > &local_origin)
void setJointVel(int i, btScalar qdot)
btVector3 m_baseTorque
btScalar getJointTorque(int i) const
btScalar m_linearDamping
bool hasFixedBase() const
const btQuaternion & getInterpolateWorldToBaseRot() const
bool isLinkAndAllAncestorsStaticOrKinematic(const int i) const
void clearConstraintForces()
btMatrix3x3 m_cachedInertiaTopLeft
void addLinkConstraintTorque(int i, const btVector3 &t)
bool m_cachedInertiaValid
void setupSpherical(int i, btScalar mass, const btVector3 &inertia, int parent, const btQuaternion &rotParentToThis, const btVector3 &parentComToThisPivotOffset, const btVector3 &thisPivotToThisComOffset, bool disableParentCollision=false)
virtual ~btMultiBody()
const btMultiBodyLinkCollider * getBaseCollider() const
void setJointPos(int i, btScalar q)
void setupPlanar(int i, btScalar mass, const btVector3 &inertia, int parent, const btQuaternion &rotParentToThis, const btVector3 &rotationAxis, const btVector3 &parentComToThisComOffset, bool disableParentCollision=false)
void setLinkDynamicType(const int i, int type)
static void spatialTransform(const btMatrix3x3 &rotation_matrix, const btVector3 &displacement, const btVector3 &top_in, const btVector3 &bottom_in, btVector3 &top_out, btVector3 &bottom_out)
void fillConstraintJacobianMultiDof(int link, const btVector3 &contact_point, const btVector3 &normal_ang, const btVector3 &normal_lin, btScalar *jac, btAlignedObjectArray< btScalar > &scratch_r, btAlignedObjectArray< btVector3 > &scratch_v, btAlignedObjectArray< btMatrix3x3 > &scratch_m) const
btTransform getBaseWorldTransform() const
btVector3 localPosToWorld(int i, const btVector3 &local_pos) const
bool isBaseStaticOrKinematic() const
void setupRevolute(int i, btScalar mass, const btVector3 &inertia, int parentIndex, const btQuaternion &rotParentToThis, const btVector3 &jointAxis, const btVector3 &parentComToThisPivotOffset, const btVector3 &thisPivotToThisComOffset, bool disableParentCollision=false)
bool m_kinematic_calculate_velocity
btScalar m_sleepTimer
btMatrix3x3 m_cachedInertiaTopRight
btScalar getBaseMass() const
btAlignedObjectArray< btScalar > m_deltaV
void updateLinksDofOffsets()
virtual int calculateSerializeBufferSize() const
bool isLinkKinematic(const int i) const
void setupFixed(int i, btScalar mass, const btVector3 &inertia, int parent, const btQuaternion &rotParentToThis, const btVector3 &parentComToThisPivotOffset, const btVector3 &thisPivotToThisComOffset, bool deprecatedDisableParentCollision=true)
bool m_internalNeedsJointFeedback
the m_needsJointFeedback gets updated/computed during the stepVelocitiesMultiDof and it for internal ...
const btQuaternion & getParentToLocalRot(int i) const
btAlignedObjectArray< btScalar > m_splitV
const btVector3 & getBaseInertia() const
void addJointTorqueMultiDof(int i, int dof, btScalar Q)
const btQuaternion & getWorldToBaseRot() const
btVector3 m_baseConstraintForce
btVector3 localDirToWorld(int i, const btVector3 &local_dir) const
btScalar getJointVel(int i) const
bool isLinkStaticOrKinematic(const int i) const
void forwardKinematics(btAlignedObjectArray< btQuaternion > &world_to_local, btAlignedObjectArray< btVector3 > &local_origin)
void applyDeltaVeeMultiDof(const btScalar *delta_vee, btScalar multiplier)
const btVector3 getBaseVel() const
btScalar * getJointVelMultiDof(int i)
btMultiBody(int n_links, btScalar mass, const btVector3 &inertia, bool fixedBase, bool canSleep, bool deprecatedMultiDof=true)
void saveKinematicState(btScalar timeStep)
void compTreeLinkVelocities(btVector3 *omega, btVector3 *vel) const
void clearForcesAndTorques()
const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
const btScalar & z() const
Return the z value.
Definition btQuadWord.h:117
const btScalar & y() const
Return the y value.
Definition btQuadWord.h:115
void setValue(const btScalar &_x, const btScalar &_y, const btScalar &_z)
Set x,y,z and zero w.
Definition btQuadWord.h:149
const btScalar & x() const
Return the x value.
Definition btQuadWord.h:113
The btQuaternion implements quaternion to perform linear algebra rotations in combination with btMatr...
void serialize(struct btQuaternionData &dataOut) const
btQuaternion inverse() const
Return the inverse of this quaternion.
btQuaternion & normalize()
Normalize the quaternion Such that x^2 + y^2 + z^2 +w^2 = 1.
virtual btChunk * allocate(size_t size, int numElements)=0
virtual void * getUniquePointer(void *oldPtr)=0
virtual void serializeName(const char *ptr)=0
virtual const char * findNameForPointer(const void *ptr) const =0
virtual void finalizeChunk(btChunk *chunk, const char *structType, int chunkCode, void *oldPtr)=0
static void calculateVelocity(const btTransform &transform0, const btTransform &transform1, btScalar timeStep, btVector3 &linVel, btVector3 &angVel)
The btTransform class supports rigid transforms with only translation and rotation and no scaling/she...
Definition btTransform.h:30
void setRotation(const btQuaternion &q)
Set the rotational element by btQuaternion.
void setIdentity()
Set this transformation to the identity.
void setOrigin(const btVector3 &origin)
Set the translational element.
btVector3 can be used to represent 3D points and vectors.
Definition btVector3.h:82
const btScalar & z() const
Return the z value.
Definition btVector3.h:579
btScalar length() const
Return the length of the vector.
Definition btVector3.h:257
btVector3 cross(const btVector3 &v) const
Return the cross product between this and another vector.
Definition btVector3.h:380
btScalar dot(const btVector3 &v) const
Return the dot product.
Definition btVector3.h:229
void setValue(const btScalar &_x, const btScalar &_y, const btScalar &_z)
Definition btVector3.h:640
btVector3 normalized() const
Return a normalized version of this vector.
Definition btVector3.h:949
const btScalar & x() const
Return the x value.
Definition btVector3.h:575
void setZero()
Definition btVector3.h:671
void serialize(struct btVector3Data &dataOut) const
Definition btVector3.h:1317
const btScalar & y() const
Return the y value.
Definition btVector3.h:577
These spatial algebra classes are used for btMultiBody, see BulletDynamics/Featherstone.
void addLinear(const btVector3 &linear)
void addVector(const btVector3 &angular, const btVector3 &linear)
const btVector3 & getAngular() const
const btVector3 & getLinear() const
void addAngular(const btVector3 &angular)
void setVector(const btVector3 &angular, const btVector3 &linear)
void setLinear(const btVector3 &linear)
const btVector3 & getLinear() const
void cross(const SpatialVectorType &b, SpatialVectorType &out) const
const btVector3 & getAngular() const
btScalar dot(const btSpatialForceVector &b) const
void setAngular(const btVector3 &angular)
void setVector(const btVector3 &angular, const btVector3 &linear)
void transformInverse(const SpatialVectorType &inVec, SpatialVectorType &outVec, eOutputOperation outOp=None)
void transformRotationOnly(const SpatialVectorType &inVec, SpatialVectorType &outVec, eOutputOperation outOp=None)
void transform(const SpatialVectorType &inVec, SpatialVectorType &outVec, eOutputOperation outOp=None)
void transformInverseRotationOnly(const SpatialVectorType &inVec, SpatialVectorType &outVec, eOutputOperation outOp=None)
void setMatrix(const btMatrix3x3 &topLeftMat, const btMatrix3x3 &topRightMat, const btMatrix3x3 &bottomLeftMat)